Skip to content

SimpleViewManager

罗坤 edited this page Apr 7, 2020 · 2 revisions

import com.facebook.react.uimanager.SimpleViewManager

getName

抽象方法 返回此视图管理类的名称。这将在JavaScript端requireNativeComponent()中引用。 同ReactContextBaseJavaModule#getName

Java端

@Override
public String getName(){
  return "RCTImageView";
}

JavaScript端

import { requireNativeComponent } from 'react-native';

const RKImage = requireNativeComponent('RCTImageView');

createViewInstance

抽象方法 视图在createViewInstance中创建,且应当把自己初始化为默认的状态。所有属性的设置都通过后续的updateView来进行。

  • 例子: 返回一个ReactImageView实例

com.facebook.react.views.image.ReactImageManager

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

onDropViewInstance

当自定义原生组件被卸载(Unmount)时调用,常用于一些需要额外清理的(例如关闭摄像机、停止播放视频)。

@Override
public void onDropViewInstance(Video view) {
  view.stop();
}

addEventEmitters

子类可以重写此方法,以在给定的View上安装自定义事件发射器(EventDispatcher)。 如果您的视图需要向JS发送基本触摸事件以外的事件( com.facebook.react.uimanager.events.Event)(例如滚动事件),则可能需要覆盖此方法。

@Override
protected void addEventEmitters(ThemedReactContext reactContext, T view) {
  /**
   * 实例化与(泛型T指)自定义UIManagerModule 关联的dispatcher
   * **/
  EventDispatcher dispatcher = reactContext.getNativeModule(T.class).getEventDispatcher();

  // 派发事件,与getExportedCustomDirectEventTypeConstants相对应
  dispatcher.dispatchEvent(new UIEvent(view.getId()))
}
  • 例子: Modal直接调度onRequestClose()事件

Java端

@Override
protected void addEventEmitters(ThemedReactContext reactContext, final ReactModalHostView view) {
    final EventDispatcher dispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
    
    //onRequestClose listner
    view.setOnRequestCloseListener(new ReactModalHostView.OnRequestCloseListener() {
        @Override
        public void onRequestClose(DialogInterface dialog) {
          dispatcher.dispatchEvent(new RequestCloseEvent(view.getId()));
        }
    });

    //onShow listner
    view.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
          dispatcher.dispatchEvent(new ShowEvent(view.getId()));
        }
    });
}

再配合getExportedCustomDirectEventTypeConstants为其注册直接调度类的事件

JavaScript端

import { requireNativeComponent } from 'react-native';

const Modal = requireNativeComponent('RCTModalHostView');

render(){
    return (
        <Modal
            onRequestClose={this.props.onRequestClose}
            onShow={this.props.onShow}
        >
            ...
        </Modal>
)}

onAfterUpdateTransaction

在当前更新事务所有属性都已更新时触发回调(所有@ReactProp,如自定义属性值被改变或者继承的style被改变后)。如果要重写此方法,你应该调用super.onAfterUpdateTransaction因为ViewManager父类可能正在执行这个回调。

  @Override
  protected void onAfterUpdateTransaction(SignaturePadView view) {
    super.onAfterUpdateTransaction(view);

  }

在View还未layout 时就会触发,所以加个保护

  @RequiresApi(api = Build.VERSION_CODES.KITKAT)
  @Override
  public void onAfterUpdateTransaction(SignaturePadView view) {
    if(view.isLayoutDirectionResolved())
        // ...
    }

getCommandsMap

如果<T extends ViewManager>子类希望通过UIManagerModule#dispatchViewManagerCommand接收命令,应该重写此方法。返回命令名与随后在receiveCommand方法中使用的id(通过findNodeHandle获取特定ViewManager的ViewTag)之间的映射,以达到为该特定ViewManager子类发送命令。

Java端

  public static final int COMMAND_SCROLL_TO = 1;
  public static final int COMMAND_SCROLL_TO_END = 2;

  @Override
  public Map<String,Integer> getCommandsMap() {
    Map<String, Integer> map = new HashMap<>();
    map.put("scrollTo", COMMAND_SCROLL_TO);
    map.put("scrollToEnd", COMMAND_SCROLL_TO_END);

    return map;
  }

JavaScript端 第一步:findNodeHandle(ref)直接操作获取ViewTag

import { findNodeHandle } from 'react-native'

<ScrollView 
  ref={ref => {
    this._handle = findNodeHandle(ref)
  }}>
>
</ScrollView>

第二步:dispatchViewManagerCommand 发送命令

import { UIManager } from 'react-native'

UIManager.dispatchViewManagerCommand(
  this._handle,  // 告诉原生需要定位到的组件
  UIManager.RCTScrollView.Commands.scrollTo,  // 原生getCommandsMap提前定义好的命令
  [x, y, animated],  // 携带的参数ReadableArray
)

receiveCommand

使用此方法接收来自UIManagerModule#dispatchViewManagerCommand的命令。

Java端

  @Override
  public void receiveCommand(
    ScrollViewManager view,
    int commandType, 
    @Nullable ReadableArray args) {
    switch (commandType) {
      case COMMAND_SCROLL_TO:{
          view.scrollTo(
                (int)args.getDouble(0),
                (int)args.getDouble(1),
                args.getBoolean(2));
          return;  // 结束switch判断
      }
      case COMMAND_SCROLL_TO_END:{
          boolean animated = args.getBoolean(0);
          view.scrollToEnd(animated);
          return;
      }
      default:
        throw new IllegalArgumentException(String.format(
            "Unsupported command %d received by %s.",
            commandType,
            getClass().getSimpleName()));
    }
  }

Q:和Module的@ReactMethod有什么区别❓
A:Command模式只负责发送事件,不能使用callback和promise,即无任何返回值

getExportedCustomBubblingEventTypeConstants

返回传递给JS的配置数据映射,该映射定义了可以放置在本机视图上的合格事件。 这应该返回冒泡的直接分派事件类型,并指定使用哪种名称来订阅任何一种形式(冒泡/捕获)。 同getExportedCustomDirectEventTypeConstants,但应通过冒泡触发事件。 返回格式应遵循下面的格式:

{
  "onTwirl": {
    "phasedRegistrationNames": {
        "bubbled": "onTwirl",
        "captured": "onTwirlCaptured"
    }
  }
}

https://stackoverflow.com/questions/34739670/creating-custom-ui-component-for-android-on-react-native-how-to-send-data-to-js/44207488#44207488

getExportedCustomDirectEventTypeConstants

返回传递给JS的配置数据映射(Map),该映射键(key)为原生视图的事件<T extends com.facebook.react.uimanager.events.Event>类常量,值(value)为注册给JS的MapBuilder.of("registrationName"," -自定义事件- ")。 原生事件应返回非冒泡(non-bubbling)的直接调度(directly-dispatched)事件类型。常和addEventEmitters配合使用。 返回格式应遵循下面的格式:

{
  "onTwirl": {
    "registrationName": "onTwirl"
  }
}
  • 例如: 向JS端注册Modal的onRequestCloseonShow直接调度类监听事件。
  import com.facebook.react.common.MapBuilder; 

  @Override
  public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
    return MapBuilder.<String, Object>builder()
      .put(RequestCloseEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRequestClose"))
      .put(ShowEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShow"))
      .build();
  }

getExportedViewConstants

返回JavaScript可访问的特定常量的映射对象。这些常量是可通过UIManager.<ViewName>.Constants进行访问。

  @Override
  public Map<String, Object> getExportedViewConstants(){
    final Map<String, Object> constants = new HashMap<>();
    constants.put("APPID", "1234567890");
    return constants;
  }
Clone this wiki locally