這里有很多本地的 UI 部件準(zhǔn)備被用到最新的應(yīng)用程序中 - 其中一些是平臺(tái)的一部分,其他的部分可以作為第三方庫來使用,而且仍然還有更多的部分可能是在你自己的投資組合中使用。React Native 已經(jīng)將幾個(gè)最關(guān)鍵的平臺(tái)組件進(jìn)行了打包,如同 ScrollView
和 TextInput
,但是并不是所有都被打包了,所以當(dāng)然也不可能是您以前寫的應(yīng)用程序。幸運(yùn)的是,通過使用 React Native 應(yīng)用程序可以很容易的將現(xiàn)有的組件進(jìn)行無縫集成打包。
就如同本地模塊指南,這是一個(gè)建立在假定你對(duì) Android SDK 編程有些熟悉的基礎(chǔ)上的更高級(jí)的指南。本指南將顯示你該如何構(gòu)建一個(gè)本地的 UI 組件, 幫助你遍歷執(zhí)行可用核心 React Native
庫中可以使用的現(xiàn)有的 ImageViewcomponent 的一個(gè)子集。
在本例中我們將要完全了解實(shí)施要求來實(shí)現(xiàn)在 JavaScript 中允許使用 ImageViews。
本地視圖是由擴(kuò)展 ViewManage
或者更普遍的 SimpleViewManager
所創(chuàng)建和操縱的。在這種情況下 SimpleViewManager
是很方便的,因?yàn)樗m用于普遍的屬性,比如背景顏色、 不透明度和 Flexbox 布局。當(dāng)然也有其他例子,當(dāng)您在使用 FrameLayout 進(jìn)行包裝組件的時(shí)候,那么這時(shí)候您需要使用 ViewManage
,比如 ProgressBar。
這些子類在本質(zhì)上是很單一的 — — 每個(gè)子類之中只有一個(gè)實(shí)例是通過這個(gè)橋接器創(chuàng)建的。他們將本地視圖傳遞到了NativeViewHierarchyManager
之中,這代表回到了通過使用它們?cè)嫉姆椒▉碓O(shè)置并更新這些必要的視圖的屬性。ViewManagers
通常也是這些視圖的代表,它通過該橋接器將事件發(fā)送回 JavaScript。
傳遞一個(gè)視圖很簡單:
1.創(chuàng)建 ViewManager 子類
2.使用 @UIProp
注釋視圖屬性
3.執(zhí)行 createViewInstance
方法
4.執(zhí)行 updateView
方法
5.在應(yīng)用程序軟件包中的 createViewManagers
中注冊(cè)管理器
6.執(zhí)行 JavaScript 模塊
ViewManager
子類在本示例中,我們通過繼承 ReactImageView
類型的 SimpleViewManager
來創(chuàng)建的視圖管理器類 ReactImageManager
。它是由管理器管理的對(duì)象類型,這將成為一個(gè)本地視圖。通過 getName
返回的名字將被用來從 Javascript 中引用本地視圖類型。
...public class ReactImageManager extends SimpleViewManager<ReactImageView> { public static final String REACT_CLASS = "RCTImageView"; @Override public String getName() { return REACT_CLASS; }
我們?cè)?JavaScript 中使用 @UIProp
來注釋需要被反映出來的屬性。目前支持的類型有 BOOLEAN
, NUMBER
, STRING
,MAP
和 ARRAY
。每個(gè)屬性都被聲明為公共靜態(tài)最終字符串常量,并且給它們分配的值在 JavaScript 中都會(huì)成為屬性的名稱。
@UIProp(UIProp.Type.STRING) public static final String PROP_SRC = "src"; @UIProp(UIProp.Type.NUMBER) public static final String PROP_BORDER_RADIUS = "borderRadius"; @UIProp(UIProp.Type.STRING) public static final String PROP_RESIZE_MODE = ViewProps.RESIZE_MODE;
createViewInstance
方法我們使用 CreateViewInstance
方法來創(chuàng)建視圖,視圖應(yīng)將其自身初始化到默認(rèn)狀態(tài),然后任何屬性都會(huì)通過后續(xù)調(diào)用updateView
來進(jìn)行設(shè)置。
@Override public ReactImageView createViewInstance(ThemedReactContext context) { return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), mCallerContext); }
updateView
方法和 iOS 中有些不同的是在 Android 中,不是通過自動(dòng)調(diào)用 setter 方法來給一個(gè)視圖的屬性進(jìn)行賦值; 對(duì)于 Android 而言,你需要通過您的 ViewManager
中的 updateView
方法手動(dòng)調(diào)用 setter。從 CatalystStylesDiffMap
中提取出來值,并且傳遞給視圖實(shí)例。它是通過 updateView
和視圖類的組合來檢查屬性的有效性,并采取相應(yīng)的行動(dòng)。
@Override public void updateView(final ReactImageView view, final CatalystStylesDiffMap props) { super.updateView(view, props); if (props.hasKey(PROP_RESIZE_MODE)) { view.setScaleType( ImageResizeMode.toScaleType(props.getString(PROP_RESIZE_MODE))); } if (props.hasKey(PROP_SRC)) { view.setSource(props.getString(PROP_SRC)); } if (props.hasKey(PROP_BORDER_RADIUS)) { view.setBorderRadius(props.getFloat(PROP_BORDER_RADIUS, 0.0f)); } view.maybeUpdateView(); } }
ViewManager
在 Java 中的最后一步是通過應(yīng)用程序包的成員函數(shù) createViewManagers
在應(yīng)用程序中注冊(cè) ViewManager,這恰巧和Native Modules 有些相似。
@Override public List<ViewManager> createViewManagers( ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new ReactImageManager() ); }
最后一步就是創(chuàng)建 JavaScript 模塊來為您的新視圖的用戶定義 Java 和 JavaScript 之間的連接層。大量工作都是由 Java 和 JavaScript 中的 React 代碼所完成,那么所有留給你的工作就是去描述 propTypes
。
// ImageView.jsvar { requireNativeComponent } = require('react-native');var iface = { name: 'ImageView', propTypes: { src: PropTypes.string, borderRadius: PropTypes.number, resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']), }, };module.exports = requireNativeComponent('RCTImageView', iface);
requireNativeComponent
通常具有兩個(gè)參數(shù),第一個(gè)是本地視圖的名稱,第二個(gè)是描述組件接口的對(duì)象。組件接口應(yīng)該聲明一個(gè)友好的名稱
在調(diào)試消息中使用,并且必須聲明本地視圖所反映的 propTypes
。PropTypes
用于檢查用戶使用本地視圖的有效性。
現(xiàn)在我們知道了如何公開使用 JS 中那些可以輕松控制的本地視圖組件。但是我們?cè)撊绾翁幚碛脩舻氖录?,比如捏拉縮放或平移?當(dāng)本地事件發(fā)生的時(shí)候,本地代碼應(yīng)該把事件傳遞給視圖中的 JavaScript 代表,并且這兩個(gè)視圖都與getId()
方法返回的值相連接。
class MyCustomView extends View { ... public void onReceiveNativeEvent() { WritableMap event = Arguments.createMap(); event.putString("message", "MyMessage"); ReactContext reactContext = (ReactContext)getContext(); reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( getId(), "topChange", event); } }
名字為 topChange
的事件對(duì)應(yīng)于 JavaScript 里面的 onChange
回調(diào) (映射是在 UIManagerModuleConstants.java
里面)。使用原始的事件來調(diào)用此回調(diào)。對(duì)于該事件,我們通常在包裝組件中對(duì)它進(jìn)行加工來形成一個(gè)更簡單的 API。
// MyCustomView.jsclass MyCustomView extends React.Component { constructor() { this._onChange = this._onChange.bind(this); } _onChange(event: Event) { if (!this.props.onChange) { return; } this.props.onChange(event.nativeEvent.message); } render() { return <RCTMyCustomView {...this.props} onChange={this._onChange} />; } } MyCustomView.propTypes = { /** * Callback that is called continuously when the user is dragging the map. */ onChange: React.PropTypes.func, ... };
更多建議: