React Native之学习篇三

      有很多原生UI小部件可以在最新的应用程序中使用 - 其中一些是平台的一部分,另外一些则作为第三方库提供,而且还可能在您自己的产品组合中使用。 React Native有几个已经包装好的最关键的平台组件,像ScrollView和TextInput,但不是所有的,当然也不是你自己为以前的应用程序编写的。 幸运的是,将这些现有的组件与您的React Native应用程序无缝集成是非常简单的。

就像本地模块指南一样,这也是一个更高级的指南,假设您对Android SDK编程有些熟悉。 本指南将向您展示如何构建本地UI组件,引导您完成核心React Native库中现有ImageView组件的一个子集。

ImageView 实例

在这个例子中,我们将逐步介绍实现需求以允许在JavaScript中使用ImageViews。

通过扩展ViewManager或更常见的SimpleViewManager来创建和操作本地视图。 SimpleViewManager在这种情况下很方便,因为它应用了常见的属性,如背景颜色,不透明度和Flexbox布局。

这些子类基本上是单一的 - 每个桥梁只创建一个实例。他们将原生视图传递给NativeViewHierarchyManager,然后委托它们根据需要设置和更新视图的属性。 ViewManagers通常也是视图的代表,通过桥将事件发送回JavaScript。

自动传递视图很简单:

1.创建ViewManager子类。
2.实现createViewInstance方法
3.使用@ReactProp(或@ReactPropGroup)注释公开视图属性设置器
4.在应用程序包的createViewManagers中注册管理器。
5.实现JavaScript模块

1. 创建 ViewManager 的子类

在这个例子中,我们创建了扩展了ReactImageView类型的SimpleViewManager的视图管理器类ReactImageManager。 ReactImageView是由管理器管理的对象的类型,这将是自定义的本地视图。 由getName返回的名称用于引用来自JavaScript的原生视图类型。

...

public class ReactImageManager extends SimpleViewManager<ReactImageView> {

  public static final String REACT_CLASS = "RCTImageView";

  @Override

  public String getName() {

    return REACT_CLASS;

  }

2. 实现createViewInstance 的方法

视图是在createViewInstance方法中创建的,视图应该以默认状态初始化自己,任何属性都将通过后续调用updateView来设置。

@Override

public ReactImageView createViewInstance(ThemedReactContext context) {

     return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), mCallerContext);

}

3.使用@ReactProp(或@ReactPropGroup)注释公开视图属性设置器

要在JavaScript中反映的属性需要作为使用@ReactProp(或@ReactPropGroup)注释的setter方法公开。 Setter方法应该将视图更新(当前视图类型)作为第一个参数,将属性值更新作为第二个参数。安装者应被宣布为无效的方法,并应公开。发送给JS的属性类型是根据setter的value参数的类型自动确定的。目前支持以下类型的值:boolean,int,float,double,String,Boolean,Integer,ReadableArray,ReadableMap。

Annotation @ReactProp有一个String类型的强制参数名称。分配给链接到setter方法的@ReactProp注释的名称用于引用JS端的属性。

除了名称,@ReactProp注释可能需要以下可选参数:defaultBoolean,defaultInt,defaultFloat。这些参数应该是相应的基本类型(相应的boolean,int,float),当setter所引用的属性已经从组件中移除时,提供的值将被传递给setter方法。请注意,只有基本类型才提供“默认”值,如果setter是复杂类型的,那么在相应属性被删除的情况下,null将被提供为默认值。

使用@ReactPropGroup注解的方法的setter声明要求与@ReactProp不同,请参阅@ReactPropGroup注释类文档以获得更多关于它的信息。

重要!在ReactJS更新属性值将导致setter方法调用。请注意,我们可以更新组件的方法之一是删除之前设置的属性。在这种情况下,setter方法也会被调用,以通知视图管理器属性已经改变。在这种情况下,将提供“默认”值(对于原始类型“默认”,可以使用默认布尔值,默认浮动等参数@ReactProp注释,复杂类型设置将调用值设置为null)。

@ReactProp(name = "src")

  public void setSrc(ReactImageView view, @Nullable ReadableArray sources) {

    view.setSource(sources);

  }

  @ReactProp(name = "borderRadius", defaultFloat = 0f)

  public void setBorderRadius(ReactImageView view, float borderRadius) {

    view.setBorderRadius(borderRadius);

  }

  @ReactProp(name = ViewProps.RESIZE_MODE)

  public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {

    view.setScaleType(ImageResizeMode.toScaleType(resizeMode));

  }

4.注册ViewManager

最后的Java步骤是将ViewManager注册到应用程序,这通过应用程序包成员函数createViewManagers以类似于本机模块的方式进行。

  @Override

  public List<ViewManager> createViewManagers(

                            ReactApplicationContext reactContext) {

    return Arrays.<ViewManager>asList(

      new ReactImageManager()

    );

  }

5.实现Javascript模块

最后一步是创建JavaScript模块,为新视图的用户定义Java和JavaScript之间的接口层。 大部分的工作都是由Java和JavaScript中的内部React代码来处理的,剩下的就是描述propType。

// ImageView.js

import PropTypes from 'prop-types';

import {requireNativeComponent, ViewPropTypes} from 'react-native';

 

var iface = {

  name: 'ImageView',

  propTypes: {

    src: PropTypes.string,

    borderRadius: PropTypes.number,

    resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),

    ...ViewPropTypes, // include the default view properties

  },

};

 

module.exports = requireNativeComponent('RCTImageView', iface);

requireNativeComponent通常需要两个参数,第一个是本地视图的名称,第二个是描述组件接口的对象。 组件接口应声明用于调试消息的友好名称,并且必须声明由本地视图反映的propType。 propTypes用于检查用户使用本地视图的有效性。 请注意,如果您需要JavaScript组件来执行更多操作,比如执行自定义事件处理,您可以将本地组件包装在普通的反应组件中。 在这种情况下,你想传递包装器组件,而不是iface requireNativeComponent。 这在下面的MyCustomView示例中进行了说明。

事件

所以现在我们知道如何公开本机视图组件,我们可以很容易地从JS控制,但我们如何处理来自用户的事件,如捏缩放或平移? 当本地事件发生时,本地代码应该向View的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回调prop,请在ViewManager中重写getExportedCustomBubblingEventTypeConstants方法进行注册:

public class ReactImageManager extends SimpleViewManager<MyCustomView> {

    ...

    public Map getExportedCustomBubblingEventTypeConstants() {

        return MapBuilder.builder()

            .put(

                "topChange",

                MapBuilder.of(

                    "phasedRegistrationNames",

                    MapBuilder.of("bubbled", "onChange")))

                    .build();

    }

}

这个回调是通过原始事件来调用的,我们通常在包装器组件中处理这个事件来创建一个更简单的API:

// MyCustomView.js

 

class MyCustomView extends React.Component {

  constructor(props) {

    super(props);

    this._onChange = this._onChange.bind(this);

  }

  _onChange(event: Event) {

    if (!this.props.onChangeMessage) {

      return;

    }

    this.props.onChangeMessage(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.

   */

  onChangeMessage: PropTypes.func,

  ...

};

 

var RCTMyCustomView = requireNativeComponent(`RCTMyCustomView`, MyCustomView, {

  nativeOnly: {onChange: true}

});

注意使用上面的nativeOnly。 有时候,您需要为本地组件公开某些特殊属性,但实际上并不希望它们作为相关React组件的API的一部分。 例如,Switch为原生本机事件提供了一个自定义的onChange处理函数,并公开了一个只使用布尔值而不是原始事件(类似于上面示例中的onChangeMessage)调用的onValueChange处理程序属性。 既然你不希望这些原生的属性成为API的一部分,你不想把它们放在propTypes中,但是如果你不这样做,你会得到一个错误。 解决方案只是通过nativeOnly选项来调用它们。

转载于:https://my.oschina.net/todaybamboo/blog/1608418

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值