React-Native是由ReactJS发展而来,继承了其JavaScript XML(简称JSX)和组件化等特性。JSX是一种XML语言,用于视图层级搭建。而组件化是一种设计思想,具有易于维护组合和便于扩展等优点,React-Native中无论是原生Java层,还是JS层,都遵循了这种思想。
在Android原生Java端的组件分为两种类型:视图组件(View)和功能组件(Module),React-Native官方为开发者提供了大量的常用组件,位于com.facebook.react.views包和com.facebook.react.modules包下面,基本覆盖了所有类型的组件,包括文本,输入框,图片等。
本文GradientColorView(颜色渐变视图)为例,演示如何自定义一个原生View组件,并在JS中调用。
package com.myproject;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.view.View;
public class GradientColorView extends View {
private GradientDrawable mDrawable;
private int mStartColor;
private int mEndColor;
public GradientColorView(Context context) {
super(context);
mDrawable = new GradientDrawable();
mDrawable.setOrientation(Orientation.LEFT_RIGHT);
}
public void setStartColor(int startColor) {
this.mStartColor = startColor;
}
public void setEndColor(int endColor) {
this.mEndColor = endColor;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDrawable.setBounds(0, 0, getWidth(), getHeight());
mDrawable.setColors(new int[]{mStartColor, mEndColor});
mDrawable.draw(canvas);
}
}
代码非常简单,自定义一个普通View,并提供两个控制渐变颜色的方法setStartColor和setEndColor,然后再onDraw方法里面绘制在画布上。
编写UI管理器,如果没有特殊要求,直接继承SimpleViewManager,并使用上一步的GradientColorView作为泛型类型。
这里需要实现两个简单的方法getName和createViewInstance,前者用来映射JS中的组件(后面讲到),后者用来创建View实例。
同时需要提供两个被注入的方法setStartColor和setEndColor,必须使用ReactProp注解,name值与JS中属性名保持一致。
package com.myproject;
import javax.annotation.Nullable;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
public class GradientColorViewManager extends SimpleViewManager<GradientColorView> {
// React-Native官方大多数自定义View都是用RCT开头,这里保持规范性
private static final String REACT_CLASS = "RCTGradientColorView";
@Override
public String getName() {
// 此处name在后面JS组件开发时会用到,需要统一命名
return REACT_CLASS;
}
@Override
protected GradientColorView createViewInstance(ThemedReactContext reactContext) {
// GradientColorView的实例化
return new GradientColorView(reactContext);
}
/**
* ReactProp注解方法,React-Native底层会自动反射调用,
* name字符串值与JS中配置的属性名保持一致
* customType字符串值表示颜色转换,不配置会转换异常
*
* @param view GradientColorView实例
* @param startColor 渐变起始值
*/
@ReactProp(name = "startColor", customType = "Color")
public void setStartColor(GradientColorView view, @Nullable Integer startColor) {
view.setStartColor(startColor);
}
/**
* ReactProp注解方法,React-Native底层会自动反射调用,
* name字符串值与JS中配置的属性名保持一致
* customType字符串值表示颜色转换,不配置会转换异常
*
* @param view GradientColorView实例
* @param endColor 渐变结束值
*/
@ReactProp(name = "endColor", customType = "Color")
public void setEndColor(GradientColorView view, @Nullable Integer endColor) {
view.setEndColor(endColor);
}
}
上一步中编写的GradientColorViewManager需要手动注册,否则React-Native底层无法映射识别,具体注册是在Activity中,代码如下:
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage(),
new ReactPackage() {
@Override
public List createViewManagers(
ReactApplicationContext reactContext) {
return Arrays.asList(new GradientColorViewManager());
}
@Override
public List createNativeModules(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List> createJSModules() {
return Collections.emptyList();
}
}
);
}
除了必要的MainReactPackage之外,注册了一个匿名内部类ReactPackage,包含了GradientColorViewManager。这样GradientColorViewManager的注册就完成了。
接下来需要开发JS层对应的组件了。
前三步中,Android原生组件开发完成了,但是如果要在设备中显示出来,还需要通过由Javascript层进行组件映射,如何映射是由Bridge(连接Java和Javascript的JNI库)完成的,这里不细讲。我们接下来编写桥梁另一端的代码。
前面说过,Javascript层也遵循了组件化设计思想,我们在React-Native项目根目录定义一个GradientColorView.js的文件,代码如下:
/**
* @providesModule RCTGradientColorView
*/
'use strict';
var PropTypes = require('ReactPropTypes');
var React = require('React');
var View = require('View');
var requireNativeComponent = require('requireNativeComponent');
var GradientColorView = React.createClass({
// 定义两个控制颜色的属性,与Java层GradientColorView中@ReactProp注解的方法参数保持一致
propTypes: {
...View.propTypes,
startColor: PropTypes.string,
endColor: PropTypes.string,
},
render: function() {
return (
<NativeGradientColorView
style={this.props.style}
startColor={this.props.startColor}
endColor={this.props.endColor}/>
);}
});
var NativeGradientColorView = requireNativeComponent('RCTGradientColorView', GradientColorView);
module.exports = GradientColorView;
分析以上代码,主要是由5部分组成。
1、注解部分。@providesModule注解表示当前JS组件是需要与原生组件相互映射的,其值RCTGradientColorView与前面第3步中GradientColorViewManager类中的getName()值保持一致性,这样才能完成映射关系。这里不得不提一点,ViewManager这个类设计得并不是特别合理,如果getName()的值也通过Java类注解来完成,保持和JS层的呼应关系,将更容易让人理解。
2、初始化对象。PropTypes、React、View、requireNativeComponent等对象在后面会使用到,所以需要先实例化。这一点是ReactJS的语法,有兴趣自行研究。
3、定义组件属性。最基本的View.propTypes属性,还有两个自定义的的startColor、endColor。这样使用组件的地方就可以使用如startColor=‘red’进行开发了。
4、组件渲染。这一步使用了JSX(JavaScript XML)语法,自定义了NativeGradientColorView标签,实际上是对GradientColorView做了一层包装。
5、组件导出。最后一行代码 module.exports = GradientColorView 声明了GradientColorView标签可以在其他JS文件中调用。
到这里,自定义组件GradientColorView已经开发完成了,接下来提供给开发者进行使用。
如何使用一共分两步:
1,导入声明
import GradientColorView from './GradientColorView.js';
2,作为标签使用
<GradientColorView style={{width:80,height:80}} startColor="yellow" endColor="red"/>
开发React-Native组件,涉及到Java(或Objective-C)和Javascript至少两种编程语言,流程比较繁琐,技术栈要求较高,除非迫不得已,一般不会这么做。
这里简要梳理一下步骤:
1、自定义View开发
2、编写相应ViewManager,实例化View,定义映射Name,注解API属性方法
3、Activity中注册ViewManager
4、编写Javascript组件,添加注解映射,定义标签对象、属性,提供给外部。
5、import组件,使用。
从以上步骤,大致可以了解React-Native组件的工作流程:
JSX标签解析 ——Javascript组件调用——Bridge——ViewManager反射——创建并配置View
本博客不定期持续更新,欢迎关注和交流:
http://blog.csdn.net/megatronkings