React Native学习之调用Android自定义view

前端之家收集整理的这篇文章主要介绍了React Native学习之调用Android自定义view前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

参考资料:原生UI组件
本篇文章中大部分还是来自参考资料中,还附带了一些我遇到的坑。

Android是一个开源的项目,有许多丰富并且功能强大的第三方自定义控件,那么React Native如何调用Android自定义的控件呢?请听我娓娓道来。
这里就不讲究如何自定义Android控件,假设你是一位Android经验丰富的人。

Android端代码

先看下待React-Native调用的Android自定义控件:

  1. public@H_301_13@ class@H_301_13@ CircleView@H_301_13@ extends@H_301_13@ View@H_301_13@ {@H_301_13@
  2. private@H_301_13@ final@H_301_13@ String TAG = "CircleView"@H_301_13@;
  3. private@H_301_13@ Paint mPaint; // 画笔@H_301_13@
  4. private@H_301_13@ float@H_301_13@ mRadius; // 圆的半径@H_301_13@
  5. public@H_301_13@ CircleView@H_301_13@(Context context) {
  6. super@H_301_13@(context);
  7. mPaint = new@H_301_13@ Paint();
  8. mPaint.setColor(0xAA000000@H_301_13@);
  9. }
  10. /** * 设置圆的背景色 * @param@H_301_13@ color */@H_301_13@
  11. public@H_301_13@ void@H_301_13@ setColor@H_301_13@(Integer color) {
  12. mPaint.setColor(color); // 设置画笔颜色@H_301_13@
  13. invalidate(); // 更新画板@H_301_13@
  14. }
  15. /** * 设置圆的半径 * @param@H_301_13@ radius */@H_301_13@
  16. public@H_301_13@ void@H_301_13@ setRadius@H_301_13@(Integer radius) {
  17. /** * 由于JS传过的数字是dip单位,需要转换为实际像素 * 使用com.facebook.react.uimanager包中的PixelUtil,进行转换 */@H_301_13@
  18. mRadius = PixelUtil.toPixelFromDIP(radius);
  19. invalidate();
  20. }
  21. @Override@H_301_13@
  22. protected@H_301_13@ void@H_301_13@ onDraw@H_301_13@(Canvas canvas) {
  23. super@H_301_13@.onDraw(canvas);
  24. canvas.drawCircle(mRadius,mRadius,mPaint); // 画一个半径为100px的圆@H_301_13@
  25. Log.d(TAG,"绘图"@H_301_13@);
  26. }
  27. }

接下来我们需要定义个管理这个CircleView,并将修改CircleView属性的接口暴露给React Native。原生视图需要被一个ViewManager的派生类(或者更常见的,SimpleViewManage的派生类)创建和管理。一个SimpleViewManager可以用于这个场景,是因为它能够包含更多公共的属性,譬如背景颜色、透明度、FlexBox布局等等。这些子类本质上都是单例——React Native只会为每个管理器创建一个实例。它们创建原生的视图并提供给NativeViewHierarchyManager,NativeViewHierarchyManager则会反过来委托它们在需要的时候去设置和更新视图的属性。ViewManager还会代理视图的所有委托,并给JavaScript发回对应的事件。

  1. public class@H_301_13@ CircleManager@H_301_13@ extends@H_301_13@ SimpleViewManager@H_301_13@<CircleView@H_301_13@> {@H_301_13@
  2. /** * 设置js引用名 */@H_301_13@
  3. @Override@H_301_13@
  4. public String getName() {
  5. return@H_301_13@ "MCircle"@H_301_13@;
  6. }
  7. /** * 创建UI组件实例 */@H_301_13@
  8. @Override@H_301_13@
  9. protected@H_301_13@ CircleView createViewInstance(ThemedReactContext reactContext) {
  10. return@H_301_13@ new@H_301_13@ CircleView(reactContext);
  11. }
  12. /** * 传输背景色参数 */@H_301_13@
  13. @ReactProp@H_301_13@(name = "color"@H_301_13@)
  14. public void setColor(CircleView view,Integer color) {
  15. view.setColor(color);
  16. }
  17. /** * 传输半径参数 */@H_301_13@
  18. @ReactProp@H_301_13@(name = "radius"@H_301_13@)
  19. public void setRadius(CircleView view,Integer radius) {
  20. view.setRadius(radius);
  21. }
  22. }

从这个类中可以看到这个CircleView对外提供两个属性的设置,一个是color和radius。要导出给JavaScript使用的属性,需要申明带有@ReactProp(或@ReactPropGroup)注解的设置方法方法的第一个参数是要修改属性的视图实例,第二个参数是要设置的属性值。方法的返回值类型必须为void,而且访问控制必须被声明为public。JavaScript所得知的属性类型会由该方法第二个参数的类型来自动决定。支持的类型有:boolean,int,float,double,String,Boolean,Integer,ReadableArray,ReadableMap。

@ReactProp注解必须包含一个字符串类型的参数name。这个参数指定了对应属性在JavaScript端的名字。

除了name,@ReactProp注解还接受这些可选的参数:defaultBoolean,defaultInt,defaultFloat。这些参数必须是对应的基础类型的值(也就是boolean,float),这些值会被传递给setter方法,以免JavaScript端某些情况下在组件中移除了对应的属性。注意这个”默认”值只对基本类型生效,对于其他的类型而言,当对应的属性删除时,null会作为默认值提供给方法。例如:

  1. @ReactProp@H_301_13@(name = "barWidth"@H_301_13@,defaultFloat = 1@H_301_13@f)

但是目前我还不是很了解这个defaultFloat值在什么情况下会使用到。如有读者知道,请留言告知。
在这个视图管理器重,最重要的是实现getName和createViewInstance方法。getName返回的是暴露给ReactNative的控件名字。第二个方法则是返回一个自定义View的实例。
现在已经创建了视图管理器了,就要把这个视图管理器注册到应用程序包中。在application中注册

  1. public@H_301_13@ class@H_301_13@ MainApplication@H_301_13@ extends@H_301_13@ Application@H_301_13@ implements@H_301_13@ ReactApplication@H_301_13@ {@H_301_13@
  2. private@H_301_13@ final@H_301_13@ ReactNativeHost mReactNativeHost = new@H_301_13@ ReactNativeHost(this@H_301_13@) {
  3. @Override@H_301_13@
  4. protected@H_301_13@ boolean@H_301_13@ getUseDeveloperSupport@H_301_13@() {
  5. return@H_301_13@ BuildConfig.DEBUG;
  6. }
  7. @Override@H_301_13@
  8. protected@H_301_13@ List<ReactPackage> getPackages@H_301_13@() {
  9. return@H_301_13@ Arrays.<ReactPackage>asList(
  10. new@H_301_13@ MainReactPackage(),new@H_301_13@ AppReactPackage()
  11. );
  12. }
  13. };
  14. @Override@H_301_13@
  15. public@H_301_13@ ReactNativeHost getReactNativeHost@H_301_13@() {
  16. return@H_301_13@ mReactNativeHost;
  17. }
  18. }
  1. public@H_301_13@ class@H_301_13@ AppReactPackage@H_301_13@ implements@H_301_13@ ReactPackage@H_301_13@ {@H_301_13@ @Override public@H_301_13@ List@H_301_13@<NativeModule> createNativeModules(ReactApplicationContext reactContext) { return@H_301_13@ Collections.emptyList(); } @Override public@H_301_13@ List@H_301_13@<Class@H_301_13@<? extends@H_301_13@ JavaScriptModule@H_301_13@>> createJSModules@H_301_13@() {@H_301_13@ return@H_301_13@ Collections.emptyList(); } @Override public@H_301_13@ List@H_301_13@<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return@H_301_13@ Arrays.<ViewManager>asList( new@H_301_13@ CircleManager() ); } }@H_301_13@@H_301_13@@H_301_13@

把这个视图管理类注册到应用程序包的createViewManagers里。

React Native模块代码

看下Js的代码
新建一个circle.js文件内容如下

  1. import React,{ Component,PropTypes } from@H_301_13@ 'react'@H_301_13@;
  2. import {
  3. View,requireNativeComponent,processColor // 字符Color转换为数字@H_301_13@
  4. } from@H_301_13@ 'react-native'@H_301_13@;
  5. //requireNativeComponent函数中的第一个参数就是刚刚CircleManager.getName返回的值。@H_301_13@
  6. const@H_301_13@ RCTCircle = requireNativeComponent('MCircle'@H_301_13@,{
  7. propTypes: {
  8. color: PropTypes.number,radius: PropTypes.number,...View.propTypes // 包含默认的View的属性@H_301_13@
  9. },});
  10. module.exports=RCTCircle;

调用的js中,如下调用

  1. import React,PropTypes } from 'react'@H_301_13@; import { AppRegistry,StyleSheet,Text,View,processColor,} from 'react-native'@H_301_13@; //如果当前的js和circle.js为同级目录的话,就如下调用,后面不用写成from 'circle.js'!!!@H_301_13@ import RCTCircle from 'circle'@H_301_13@; export default@H_301_13@ class@H_301_13@ MainComponent@H_301_13@ extends@H_301_13@ Component@H_301_13@ {@H_301_13@ render() { return@H_301_13@ ( <View> <Circle style=@H_301_13@@H_301_13@@H_301_13@{{width@H_301_13@: 100,height@H_301_13@: 100}}@H_301_13@ color={processColor('#ff0000'@H_301_13@)} radius={50@H_301_13@} /> </View> ); } }@H_301_13@@H_301_13@@H_301_13@

requireNativeComponent通常接受两个参数,第一个参数是原生视图的名字,而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的name,这个name是用来在调试信息中显示,而不是给React-Native调用的名字,这个name可有可无。组件接口还必须声明propTypes字段,PropType是说明该属性的类型,需要和native的保持一致,用来对应到原生视图上。
这里还需要说明的是,通过视图管理器暴露出来的属性,例如该例子中的color和radius,不能写在style={}中,在style={}只支持ReactNative原生的属性。而试图管理器暴露出来的属性,与style平级的,正如例子中展示的那样子。

当然还有一种就是如果试图管理器提供的view,在React-Native这里还需要在封装下,例如传递一些事件或者修改一些属性值什么的,可以在requireNativeComponent函数中第二个参数传component,例如:

  1. 'use strict'@H_301_13@;
  2. import React,PropTypes } from 'react'@H_301_13@;
  3. import {
  4. View,processColor // 字符Color转换为数字@H_301_13@
  5. } from 'react-native'@H_301_13@;
  6. const@H_301_13@ MCircle = requireNativeComponent('MCircle'@H_301_13@,});
  7. class@H_301_13@ Circle@H_301_13@ extends@H_301_13@ Component@H_301_13@ {@H_301_13@
  8. static@H_301_13@ propTypes = {
  9. radius: PropTypes.number,color: PropTypes.string,// 这里传过来的是string@H_301_13@
  10. ...View.propTypes // 包含默认的View的属性@H_301_13@
  11. }
  12. render() {
  13. const@H_301_13@ { style,radius,color } = this.props;
  14. return@H_301_13@ (
  15. <MCircle
  16. style={style}
  17. radius={radius}
  18. color={processColor(color)}
  19. />
  20. );
  21. }
  22. }
  23. module.exports = Circle;

猜你在找的React相关文章