在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ Native UI 組件(iOS)
JavaScript 環(huán)境
計時器
Native 模塊(iOS)
入門
在設備上運行
ProgressBarAndroid
iOS 應用程序狀態(tài)
網(wǎng)絡
ToolbarAndroid
測試
輔助功能
網(wǎng)絡信息
DrawerLayoutAndroid
樣式表
手勢應答系統(tǒng)
與現(xiàn)有的應用程序集成
樣式
教程
不透明觸摸
調試 React Native 應用
iOS 活動指示器
導航器
無反饋觸摸
動畫布局
Web 視圖
鏈接庫
像素比率
React Native 官網(wǎng)首頁介紹
iOS 導航器
交互管理器
全景響應器
SwitchAndroid
TabBarIOS.Item
相機滾動
ToastAndroid
iOS 震動
BackAndroid
文本輸入
iOS 選擇器
應用程序注冊表
iOS 開關
滾動視圖
iOS 日期選擇器
iOS 警告
iOS 鏈接
視圖
圖片
列表視圖
異步存儲
Native UI 組件(Android)
iOS 滑塊
Map 視圖
高亮觸摸
iOS 推送通知
文本
定位
iOS 狀態(tài)欄
Native UI 組件(iOS)
在設備上運行(Android)
Native 模塊(Android)
Flexbox
已知 Issues
iOS 選項卡
安裝 Android 運行環(huán)境

Native UI 組件(iOS)

有許多 native UI 小部件可以應用到最新的應用程序中——其中一些是平臺的一部分,另外的可以用作第三方庫,并且更多的是它們可以用于你自己的選集中。React Native 有幾個最關鍵的平臺組件已經(jīng)包裝好了,如 ScrollViewTextInput,但不是所有的組件都被包裝好了,當然了,你為先前的應用程序寫的組件肯定沒有包裝好。幸運的是,為了與 React Native 應用程序無縫集成,將現(xiàn)存組件包裝起來是非常容易實現(xiàn)的。

正如 native 模塊指南,這也是一種更高級的指南,假定你對 iOS 編程有一定的了解。本指南將向你展示如何構建一個本地的 UI 組件,帶你實現(xiàn)在核心 React Native 庫中可用的現(xiàn)存的 MapView 組件的子集。

iOS MapView 示例

如果說我們想在我們的應用程序中添加一個交互式的 Map——不妨用 MKMapView,我們只需要讓它在 JavaScript 中可用。

Native 視圖是通過 RCTViewManager 的子類創(chuàng)建和操做的。這些子類的功能與視圖控制器很相似,但本質上它們是單件模式——橋只為每一個子類創(chuàng)建一個實例。它們將 native 視圖提供給 RCTUIManager,它會傳回到 native 視圖來設置和更新的必要的視圖屬性。RCTViewManager 通常也是視圖的代表,通過橋將事件發(fā)送回 JavaScript。

發(fā)送視圖是很簡單的:

  • 創(chuàng)建基本的子類。

  • 添加標記宏 RCT_EXPORT_MODULE()。

  • 實現(xiàn) -(UIView *)view 方法。
// RCTMapManager.m
#import <MapKit/MapKit.h>
#import "RCTViewManager.h"
@interface RCTMapManager : RCTViewManager
@end
@implementation RCTMapManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
  return [[MKMapView alloc] init];
}
@end

然后你需要一些 JavaScript 使之成為有用的 React 組件:

// MapView.js
var { requireNativeComponent } = require('react-native');
module.exports = requireNativeComponent('RCTMap', null);

現(xiàn)在這是 JavaScript 中一個功能完整的 native map 視圖組件了,包括 pinch-zoom 和其他 native 手勢支持。但是我們還不能用 JavaScript 來真正的控制它。

屬性

為了使該組件更可用,我們可以做的第一件事是連接一些 native 屬性。比如說我們希望能夠禁用音高控制并指定可見區(qū)域。禁用音高是一個簡單的布爾值,所以我們只添加這一行:

// RCTMapManager.m
RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)

注意我們顯式的指定類型為 BOOL——當談到連接橋時,React Native 使用 hood 下的 RCTConvert 來轉換所有不同的數(shù)據(jù)類型,且錯誤的值會顯示明顯的 “RedBox” 錯誤使你知道這里有 ASAP 問題。當一切進展順利時,這個宏就會為你處理整個實現(xiàn)。

現(xiàn)在要真正的實現(xiàn)禁用音高,我們只需要在 JS 中設置如下所示屬性:

// MyApp.js
<MapView pitchEnabled={false} />

但是這不是很好記錄——為了知道哪些屬性可用以及它們接收了什么值,你的新組件的客戶端需要挖掘 objective-C 代碼。為了更好的實現(xiàn)這一點,讓我們做一個包裝器組件并用 React PropTypes 記錄接口:

// MapView.js
var React = require('react-native');
var { requireNativeComponent } = React;
class MapView extends React.Component {
  render() {
    return <RCTMap {...this.props} />;
  }
}
var RCTMap = requireNativeComponent('RCTMap', MapView);
MapView.propTypes = {
  /**
   * When this property is set to `true` and a valid camera is associated
   * with the map, the camera’s pitch angle is used to tilt the plane
   * of the map. When this property is set to `false`, the camera’s pitch
   * angle is ignored and the map is always displayed as if the user
   * is looking straight down onto it.
   */
  pitchEnabled: React.PropTypes.bool,
};
module.exports = MapView;

現(xiàn)在我們有一個很不錯的已記錄的包裝器組件,它使用非常容易。注意我們?yōu)樾碌?MapView 包裝器組件將第二個參數(shù)從 null 改為 requireNativeComponent。這使得基礎設施驗證了 propTypes 匹配native 工具來減少 ObjC 和 JS 代碼之間的不匹配的可能。

接下來,讓我們添加更復雜的 region 工具。從添加 native 代碼入手:

// RCTMapManager.m
RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
{
  [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];
}

好的,這顯然比之前簡單的 BOOL 情況更加復雜?,F(xiàn)在我們有一個 MKCoordinateRegion 類型,該類型需要一個轉換函數(shù),并且我們有自定義的代碼,這樣當我們從 JS 設置區(qū)域時,視圖可以產生動畫效果。還有一個 defaultView,如果 JS 發(fā)送給我們一個 null 標記,我們使用它將屬性重置回默認值。

當然你可以為你的視圖編寫任何你想要的轉換函數(shù)——下面是通過 RCTConvert 的兩類來實現(xiàn) MKCoordinateRegion 的例子:

@implementation RCTConvert(CoreLocation)
RCT_CONVERTER(CLLocationDegrees, CLLocationDegrees, doubleValue);
RCT_CONVERTER(CLLocationDistance, CLLocationDistance, doubleValue);
+ (CLLocationCoordinate2D)CLLocationCoordinate2D:(id)json
{
  json = [self NSDictionary:json];
  return (CLLocationCoordinate2D){
    [self CLLocationDegrees:json[@"latitude"]],
    [self CLLocationDegrees:json[@"longitude"]]
  };
}
@end
@implementation RCTConvert(MapKit)
+ (MKCoordinateSpan)MKCoordinateSpan:(id)json
{
  json = [self NSDictionary:json];
  return (MKCoordinateSpan){
    [self CLLocationDegrees:json[@"latitudeDelta"]],
    [self CLLocationDegrees:json[@"longitudeDelta"]]
  };
}
+ (MKCoordinateRegion)MKCoordinateRegion:(id)json
{
  return (MKCoordinateRegion){
    [self CLLocationCoordinate2D:json],
    [self MKCoordinateSpan:json]
  };
}

這些轉換函數(shù)是為了安全地處理任何 JSON 而設計的,當出現(xiàn)丟失的鍵或開發(fā)人員錯誤操作時,JS 可能向它們拋出 “RedBox” 錯誤并返回標準的初始化值。

為完成對 region 工具的支持,我們需要把它記錄到 propTypes中(否則我們將得到一個錯誤,即 native 工具沒有被記錄),然后我們就可以按照設置其他工具的方式來設置它:

// MapView.js
MapView.propTypes = {
  /**
   * When this property is set to `true` and a valid camera is associated
   * with the map, the camera’s pitch angle is used to tilt the plane
   * of the map. When this property is set to `false`, the camera’s pitch
   * angle is ignored and the map is always displayed as if the user
   * is looking straight down onto it.
   */
  pitchEnabled: React.PropTypes.bool,
  /**
   * The region to be displayed by the map.
   *
   * The region is defined by the center coordinates and the span of
   * coordinates to display.
   */
  region: React.PropTypes.shape({
    /**
     * Coordinates for the center of the map.
     */
    latitude: React.PropTypes.number.isRequired,
    longitude: React.PropTypes.number.isRequired,
    /**
     * Distance between the minimum and the maximum latitude/longitude
     * to be displayed.
     */
    latitudeDelta: React.PropTypes.number.isRequired,
    longitudeDelta: React.PropTypes.number.isRequired,
  }),
};
// MyApp.js
  render() {
    var region = {
      latitude: 37.48,
      longitude: -122.16,
      latitudeDelta: 0.1,
      longitudeDelta: 0.1,
    };
    return <MapView region={region} />;
  }

在這里你可以看到該區(qū)域的形狀在 JS 文檔中是顯式的——理想情況下我們可以生成一些這方面的東西,但是這沒有實現(xiàn)。

事件

所以現(xiàn)在我們有一個 native map 組件,可以從 JS 很容易的控制,但是我們如何處理來自用戶的事件,如 pinch-zooms 或平移來改變可見區(qū)域?關鍵是要使 RCTMapManager 成為它發(fā)送的所有視圖的代表,并把事件通過事件調度器發(fā)送給 JS。這看起來如下所示(從整個實現(xiàn)中簡化出來的部分):

// RCTMapManager.m
#import "RCTMapManager.h"
#import <MapKit/MapKit.h>
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "UIView+React.h"
@interface RCTMapManager() <MKMapViewDelegate>
@end
@implementation RCTMapManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
  MKMapView *map = [[MKMapView alloc] init];
  map.delegate = self;
  return map;
}
#pragma mark MKMapViewDelegate
- (void)mapView:(RCTMap *)mapView regionDidChangeAnimated:(BOOL)animated
{
  MKCoordinateRegion region = mapView.region;
  NSDictionary *event = @{
    @"target": mapView.reactTag,
    @"region": @{
      @"latitude": @(region.center.latitude),
      @"longitude": @(region.center.longitude),
      @"latitudeDelta": @(region.span.latitudeDelta),
      @"longitudeDelta": @(region.span.longitudeDelta),
    }
  };
  [self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
}

你可以看到我們設置管理器為它發(fā)送的每個視圖的代表,然后在代表方法 -mapView:regionDidChangeAnimated: 中,區(qū)域與 reactTag 目標相結合來產生事件,通過 sendInputEventWithName:body 分派到你應用程序中相應的 React 組件實例中。事件名稱 @"topChange" 映射到從 JavaScript 中回調的 onChange這里查看 mappings )。原始事件調用這個回調,我們通常在包裝器組件中處理這個過程來實現(xiàn)一個簡單的 API:

// MapView.js
class MapView extends React.Component {
  constructor() {
    this._onChange = this._onChange.bind(this);
  }
  _onChange(event: Event) {
    if (!this.props.onRegionChange) {
      return;
    }
    this.props.onRegionChange(event.nativeEvent.region);
  }
  render() {
    return <RCTMap {...this.props} onChange={this._onChange} />;
  }
}
MapView.propTypes = {
  /**
   * Callback that is called continuously when the user is dragging the map.
   */
  onRegionChange: React.PropTypes.func,
  ...
}; 

樣式

由于我們所有的 native react 視圖是 UIView 的子類,大多數(shù)樣式屬性會像你預想的一樣內存不足。然而,一些組件需要默認的樣式,例如 UIDatePicker,大小固定。為了達到預期的效果,默認樣式對布局算法來說是非常重要的,但是我們也希望在使用組件時能夠覆蓋默認的樣式。DatePickerIOS 通過包裝一個額外的視圖中的 native 組件實現(xiàn)這一功能,該額外的視圖具有靈活的樣式設計,并在內部 native 組件中使用一個固定的樣式(用從 native 傳遞的常量生成):

// DatePickerIOS.ios.js
var RCTDatePickerIOSConsts = require('NativeModules').UIManager.RCTDatePicker.Constants;
...
  render: function() {
    return (
      <View style={this.props.style}>
        <RCTDatePickerIOS
          ref={DATEPICKER}
          style={styles.rkDatePickerIOS}
          ...
        />
      </View>
    );
  }
});
var styles = StyleSheet.create({
  rkDatePickerIOS: {
    height: RCTDatePickerIOSConsts.ComponentHeight,
    width: RCTDatePickerIOSConsts.ComponentWidth,
  },
});

RCTDatePickerIOSConsts 常量是通過抓取 native 組件的實際框架從 native 中導出的,如下所示:

// RCTDatePickerManager.m
- (NSDictionary *)constantsToExport
{
  UIDatePicker *dp = [[UIDatePicker alloc] init];
  [dp layoutIfNeeded];
  return @{
    @"ComponentHeight": @(CGRectGetHeight(dp.frame)),
    @"ComponentWidth": @(CGRectGetWidth(dp.frame)),
    @"DatePickerModes": @{
      @"time": @(UIDatePickerModeTime),
      @"date": @(UIDatePickerModeDate),
      @"datetime": @(UIDatePickerModeDateAndTime),
    }
  };
}

本指南涵蓋了銜接自定義 native 組件的許多方面,但有你可能有更多需要考慮的地方,如自定義 hooks 來插入和布局子視圖。如果你想了解更多,請在源代碼中查看實際的 RCTMapManager 和其他組件。

上一篇:SwitchAndroid下一篇:無反饋觸摸