doc icon indicating copy to clipboard operation
doc copied to clipboard

如何开发一个react-native android组件

Open shexiaoheng opened this issue 9 years ago • 2 comments

首先按照官网文档的步骤来做: 1. Create the ViewManager subclass 2. Implement method createViewInstance 3. Expose view property setters using @ReactProp (or @ReactPropGroup) annotation 4. Register the ViewManager 5. Implement the JavaScript module 在native组件只有设置属性的时很按照上面的来做很容易就搞定了,但是实际开发中既然是组件,肯定会有相应的事件监听处理和外部调用的方法。

事件的处理:

对于Event的处理也有官方文档 ,不过对应的.JS文件并不健全,可以参考我写过的react-native-wheel的实现: WheelViewManager.java:

@ReactProp(name = "onItemChange", defaultBoolean = true)
    public void setOnItemChange(final LoopView view, Boolean value) {
        view.setListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(int index) {
                WritableMap event = Arguments.createMap();
                event.putInt("index", index);
                ReactContext reactContext = (ReactContext) view.getContext();
                reactContext.getJSModule(RCTEventEmitter.class)
                        .receiveEvent(view.getId(), "topChange", event);
            }
        });
    }

index.js

var iface = {
    name: 'RCTWheelView',
    propTypes: {
        onItemChange: PropTypes.func,
        values: PropTypes.array,
        isLoop: PropTypes.bool,
        selectedIndex: PropTypes.number,
        textSize: PropTypes.number,
    },
};

var MyWheelView = React.createClass({

    handleOnChange(event){
        if(this.props.onItemChange){
            this.props.onItemChange(event.nativeEvent.index);
        }
    },
    render(){
        return <NativeWheelView {...this.props} onChange = {this.handleOnChange} />;
    }
});
方法的处理:

React-Native的官方文档并没有对应的文档说明,找了好几天都没有找到相应的处理,最终无奈在react-native的github提交了一个issues,然后在@brentvatne的帮助下得以解决 参考以下内容: ReactViewPagerManager.java:

  @Override
  public Map<String,Integer> getCommandsMap() {
    return MapBuilder.of(
        "setPage",
        COMMAND_SET_PAGE,
        "setPageWithoutAnimation",
        COMMAND_SET_PAGE_WITHOUT_ANIMATION);
  }

  @Override
  public void receiveCommand(
      ReactViewPager viewPager,
      int commandType,
      @Nullable ReadableArray args) {
    Assertions.assertNotNull(viewPager);
    Assertions.assertNotNull(args);
    switch (commandType) {
      case COMMAND_SET_PAGE: {
        viewPager.setCurrentItemFromJs(args.getInt(0), true);
        return;
      }
      case COMMAND_SET_PAGE_WITHOUT_ANIMATION: {
        viewPager.setCurrentItemFromJs(args.getInt(0), false);
        return;
      }
      default:
        throw new IllegalArgumentException(String.format(
            "Unsupported command %d received by %s.",
            commandType,
            getClass().getSimpleName()));
    }
  }

ViewPagerAndroid.android.js:

 /**
   * A helper function to scroll to a specific page in the ViewPager.
   * The transition between pages will be animated.
   */
  setPage: function(selectedPage: number) {
    UIManager.dispatchViewManagerCommand(
      React.findNodeHandle(this),
      UIManager.AndroidViewPager.Commands.setPage,
      [selectedPage],
    );
  },

  /**
   * A helper function to scroll to a specific page in the ViewPager.
   * The transition between pages will be *not* be animated.
   */
  setPageWithoutAnimation: function(selectedPage: number) {
    UIManager.dispatchViewManagerCommand(
      React.findNodeHandle(this),
      UIManager.AndroidViewPager.Commands.setPageWithoutAnimation,
      [selectedPage],
    );
  },

最后就是就像@brentvatne说的 “This isn't the best place to ask this kind of question, as the comment above suggests, you should try StackOverflow.” 提问问题最好去StackOverflow ,再次感谢@brentvatne的回答。

shexiaoheng avatar Dec 03 '15 11:12 shexiaoheng

:dancer:

brentvatne avatar Dec 08 '15 07:12 brentvatne

对于方法的处理,我也写了一个例子

WheelViewManager.java

 @Override
    public Map<String,Integer> getCommandsMap() {
        return MapBuilder.of(
                "previous",
                COMMAND_PREVIOUS,
                "next",
                COMMAND_NEXT);
    }

    @Override
    public void receiveCommand(LoopView root, int commandId, ReadableArray args) {
        switch (commandId) {
            case COMMAND_PREVIOUS: {
                root.previous();
                return;
            }
            case COMMAND_NEXT: {
                root.next();
                return;
            }
            default:
                throw new IllegalArgumentException(String.format(
                        "Unsupported command %d received by %s.",
                        commandId,
                        getClass().getSimpleName()));
        }
    }

index.js

previous: function(){
        UIManager.dispatchViewManagerCommand(
            React.findNodeHandle(this.refs.wheel),
            UIManager.RCTWheelView.Commands.previous,
            null,
        );
    },
    next: function(){
        UIManager.dispatchViewManagerCommand(
            React.findNodeHandle(this.refs.wheel),
            UIManager.RCTWheelView.Commands.next,
            null,
        );
    },

使用方法

index.android.js

var AwesomeProject = React.createClass({
  previous(){
    this.refs.wheel.previous();
  },
  next(){
    this.refs.wheel.next();
  },
  finish(){
    ToastAndroid.show('select item : ' + wheelData[currentIndex] ,ToastAndroid.LONG);
  },
  onItemChange(index){
    currentIndex = index;
  },
  render: function() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome} onPress={this.previous} >
          上一个
        </Text>
        <Text style={styles.instructions} onPress={this.next} >
          下一个
        </Text>
        <Text style={styles.instructions} onPress={this.finish} >
          完成
        </Text>
        <WheelView
          style={styles.wheelview}
          onItemChange={this.onItemChange}
          values={wheelData}
          isLoop={false}
          selectedIndex={0}
          textSize={20}
          ref='wheel'
        />
      </View>
    );
  }
});

shexiaoheng avatar Dec 10 '15 02:12 shexiaoheng