Native UI 組件(Android)

2019-08-14 14:22 更新

這里有很多本地的 UI 部件準備被用到最新的應用程序中 - 其中一些是平臺的一部分,其他的部分可以作為第三方庫來使用,而且仍然還有更多的部分可能是在你自己的投資組合中使用。React Native 已經(jīng)將幾個最關鍵的平臺組件進行了打包,如同 ScrollView  TextInput,但是并不是所有都被打包了,所以當然也不可能是您以前寫的應用程序。幸運的是,通過使用 React Native 應用程序可以很容易的將現(xiàn)有的組件進行無縫集成打包。

就如同本地模塊指南,這是一個建立在假定你對 Android SDK 編程有些熟悉的基礎上的更高級的指南。本指南將顯示你該如何構建一個本地的 UI 組件, 幫助你遍歷執(zhí)行可用核心 React Native 庫中可以使用的現(xiàn)有的 ImageViewcomponent 的一個子集。

ImageView 示例

在本例中我們將要完全了解實施要求來實現(xiàn)在 JavaScript 中允許使用 ImageViews。

本地視圖是由擴展 ViewManage 或者更普遍的 SimpleViewManager 所創(chuàng)建和操縱的。在這種情況下 SimpleViewManager是很方便的,因為它適用于普遍的屬性,比如背景顏色、 不透明度和 Flexbox 布局。當然也有其他例子,當您在使用 FrameLayout 進行包裝組件的時候,那么這時候您需要使用 ViewManage ,比如 ProgressBar。

這些子類在本質(zhì)上是很單一的 — — 每個子類之中只有一個實例是通過這個橋接器創(chuàng)建的。他們將本地視圖傳遞到了NativeViewHierarchyManager 之中,這代表回到了通過使用它們原始的方法來設置并更新這些必要的視圖的屬性。ViewManagers 通常也是這些視圖的代表,它通過該橋接器將事件發(fā)送回 JavaScript。

傳遞一個視圖很簡單:

1.創(chuàng)建 ViewManager 子類
2.使用 @UIProp 注釋視圖屬性
3.執(zhí)行 createViewInstance 方法
4.執(zhí)行 updateView 方法
5.在應用程序軟件包中的 createViewManagers 中注冊管理器
6.執(zhí)行 JavaScript 模塊

1. 創(chuàng)建 ViewManager 子類

在本示例中,我們通過繼承 ReactImageView 類型的 SimpleViewManager 來創(chuàng)建的視圖管理器類 ReactImageManager。它是由管理器管理的對象類型,這將成為一個本地視圖。通過 getName 返回的名字將被用來從 Javascript 中引用本地視圖類型。

...public class ReactImageManager extends SimpleViewManager<ReactImageView> {  public static final String REACT_CLASS = "RCTImageView";  @Override
  public String getName() {    return REACT_CLASS;
  }

2. 注釋視圖屬性

我們在 JavaScript 中使用 @UIProp 來注釋需要被反映出來的屬性。目前支持的類型有 BOOLEANNUMBERSTRING,MAP 和 ARRAY。每個屬性都被聲明為公共靜態(tài)最終字符串常量,并且給它們分配的值在 JavaScript 中都會成為屬性的名稱。

  @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)建視圖,視圖應將其自身初始化到默認狀態(tài),然后任何屬性都會通過后續(xù)調(diào)用updateView 來進行設置。

  @Override
  public ReactImageView createViewInstance(ThemedReactContext context) {    return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), mCallerContext);
  }

4. 執(zhí)行 updateView 方法

和 iOS 中有些不同的是在 Android 中,不是通過自動調(diào)用 setter 方法來給一個視圖的屬性進行賦值; 對于 Android 而言,你需要通過您的 ViewManager 中的 updateView 方法手動調(diào)用 setter。從 CatalystStylesDiffMap 中提取出來值,并且傳遞給視圖實例。它是通過 updateView 和視圖類的組合來檢查屬性的有效性,并采取相應的行動。

  @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. 注冊 ViewManager

在 Java 中的最后一步是通過應用程序包的成員函數(shù) createViewManagers 在應用程序中注冊 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 通常具有兩個參數(shù),第一個是本地視圖的名稱,第二個是描述組件接口的對象。組件接口應該聲明一個友好的名稱在調(diào)試消息中使用,并且必須聲明本地視圖所反映的 propTypes。PropTypes 用于檢查用戶使用本地視圖的有效性。

事件

現(xiàn)在我們知道了如何公開使用 JS 中那些可以輕松控制的本地視圖組件。但是我們該如何處理用戶的事件呢,比如捏拉縮放或平移?當本地事件發(fā)生的時候,本地代碼應該把事件傳遞給視圖中的 JavaScript 代表,并且這兩個視圖都與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 的事件對應于 JavaScript 里面的 onChange 回調(diào) (映射是在 UIManagerModuleConstants.java 里面)。使用原始的事件來調(diào)用此回調(diào)。對于該事件,我們通常在包裝組件中對它進行加工來形成一個更簡單的 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)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號