Native UI 組件(Android)

2019-08-14 14:22 更新

這里有很多本地的 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è)子集。

ImageView 示例

在本例中我們將要完全了解實(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 模塊

1. 創(chuàng)建 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;
  }

2. 注釋視圖屬性

我們?cè)?JavaScript 中使用 @UIProp 來注釋需要被反映出來的屬性。目前支持的類型有 BOOLEANNUMBERSTRING,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;

3. 執(zhí)行 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);
  }

4. 執(zhí)行 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();
  }
}

5. 注冊(cè) 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()
    );
  }

6. 執(zhí)行 JavaScript 模塊

最后一步就是創(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,
  ...
};


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)