React Native封装Android原生控件
来源:互联网 发布:linux vi 文件末尾 编辑:程序博客网 时间:2024/05/22 09:44
第一步:
我们首先要创建一个RN项目:
react-native init 你的项目名
第二步:
是用Android studio打开RN项目中的Android项目。
在新建一个文件夹用于存放我们封装的控件,结构如下:
第三步:
创建ViewManager,比如TextViewManager,代码如下:
import android.graphics.Color;import android.util.Log;import android.view.View;import android.widget.TextView;import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.ReactContext;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.ReadableMap;import com.facebook.react.bridge.WritableMap;import com.facebook.react.uimanager.SimpleViewManager;import com.facebook.react.uimanager.ThemedReactContext;import com.facebook.react.uimanager.annotations.ReactProp;import com.facebook.react.uimanager.events.RCTEventEmitter;/** * Created by sujialong on 2017/9/1. */public class TextViewManager extends SimpleViewManager<TextView> { @Override public String getName() { return "CustomTextView"; } @Override protected TextView createViewInstance(ThemedReactContext reactContext) { final TextView textView = new TextView(reactContext);// final ThemedReactContext myContext = reactContext; //注册点击事件 textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { WritableMap event = Arguments.createMap(); event.putString("message", "MyMessage哈哈哈--自定义"); ReactContext reactContext = (ReactContext)textView.getContext(); reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( textView.getId(), "topChange", event); } }); return textView; } @ReactProp(name="text") public void setText(TextView textView,String text){ textView.setText(text); } @ReactProp(name="textSize") public void setTextSize(TextView view,float fontSize){ view.setTextSize(fontSize); } @ReactProp(name = "textColor",defaultInt = Color.BLACK) public void setTextColor(TextView view,int textColor){ view.setTextColor(textColor); }}
1.getName方法用于js端导出时,使用的控件名称。
2.createViewInstance方法用于创建控件与初始化状态。
3.使用@ReactProp注解的方法,是将js端传入的属性值导出,并且给控件设置该属性值。
@ReactProp
该注解可以传入两个参数:
1. name:js端使用时传入的参数名,必传。
2. defaultBoolean:设置默认值,可选,其他选项:defaultInt,defaultFloat。这些参数必须是对应的基础类型的值(也就是boolean,int, float),这些值会被传递给setter方法,以免JavaScript端某些情况下在组件中移除了对应的属性。
第四步:
注册ViewManager,新建一个class,名为ReactViewPackage,在这个class里面加入以下代码:
import com.facebook.react.ReactPackage;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.uimanager.ViewManager;import java.util.Arrays;import java.util.Collections;import java.util.List;/** * Created by sujialong on 2017/9/1. */public class ReactViewPackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { return Arrays.<NativeModule>asList( new ToastViewManager(reactContext) ); } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new TextViewManager() ); }}
这里面需要我们实现ReactPackage的两个方法:createViewManagers,createNativeModules。以前还有一个叫做createJSModules的方法,现在被移除掉了。其中,createNativeModules是用来添加原生模块的,比如:Toast等。createViewManagers是用来添加原生的UI组件的。
我们第一个创建的TextView是UI组件,所以我们将TextViewManager添加到createViewManagers中,如果没有引入原生模块,可以将createNativeModules方返回空数组:
@Override public List<NativeModule> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); }
第五步:
在项目的MainApplication.java文件的getPackages方法中添加,我们封装的原生模块:
@Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new ReactViewPackage() ); }
ok,到这一步我们基本的封装已经完毕。
第六步:
需要我们在js端导出所封装的原生组件,如下:
import React, {PureComponent,PropTypes} from 'react';import {requireNativeComponent,View} from 'react-native';const CustomTextView = { name:"CustomTextView", propTypes:{ "text":PropTypes.string, "textSize":PropTypes.number, "textColor":PropTypes.number, ...View.propTypes }}const RCTCustomTextView = requireNativeComponent('CustomTextView',CustomTextView,{ nativeOnly: {onChange: true}});export default class MyView extends PureComponent { _onChange = (event: Event) => { const onChangeMessage = this.props.onChangeMessage; onChangeMessage && onChangeMessage(event.nativeEvent); } render() { return ( <RCTCustomTextView {...this.props} onChange={this._onChange}/> ); }}MyView.propTypes = { onChangeMessage:PropTypes.func,};
这里,由于我们是封装的TextView,需要使用requireNativeComponent在原生代码中引用。requireNativeComponent通常接受两个参数,第一个参数是原生视图的名字,也就是我们在ViewManager中使用getName方法定义的名字,而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的name,用来在调试信息中显示;组件接口还必须声明propTypes字段,用来对应到原生视图上。这个propTypes还可以用来检查用户使用View的方式是否正确。
第六步:
使用所封装好的组件:
import React, { Component } from 'react';import { AppRegistry, StyleSheet, Text, View, DeviceEventEmitter} from 'react-native';import CustomTextView from './src/CustomTextView';
export default class CustomRnView extends Component { render() { return ( <View style={styles.container}> <CustomTextView style={styles.myTextView} text="我是封装的原生组件" textSize={15} onChangeMessage={(msg)=>{ CustomToastView.show("点到我了----",CustomToastView.SHORT); CustomToastView.getNativeClass(this._getNativeClass); this._getNativePromise(); }}/> </View> ); }}const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, myTextView:{ width:300, height:100, },});
第七步:
在项目的根目录下,运行:
react-native run-android
成功啦!!!
第八步:为原生模块添加方法
要给js端调用的方法,需要使用@ReactMethod注解:
@ReactMethodpublic void show(String message, int duration){ Toast.makeText(getReactApplicationContext(), message, duration).show();}
在js端如下调用:
import CustomToastView from './src/CustomToastView';CustomToastView.show("message",CustomToastView.SHORT);
第九步:为原生代码添加回调函数
1.使用Callback:
import com.facebook.react.bridge.Callback;//使用回调函数@ReactMethodpublic void getNativeClass(Callback callback){ callback.invoke("使用回调函数");}
在js端如下调用:
import CustomToastView from './src/CustomToastView';CustomToastView.getNativeClass((res) => { alert(res);});
2.使用Promise:
//使用promise回调 @ReactMethod public void getArguments(Boolean isResolve,Promise promise){ WritableMap map = Arguments.createMap(); map.putString("name", "Arno"); map.putString("age", "25"); if(isResolve){ promise.resolve(map); }else{ promise.reject(map.toString()); } }
在js端使用:
import CustomToastView from './src/CustomToastView';CustomToastView.getArguments(true) .then((res) => { console.log("getArguments---success"); console.log(res); },(error)=>{ console.log("getArguments---error"); console.log(res); });
3.给JS发送事件
private static final String TestEventName = "TestEventName";//发送事件,js端使用事件监听接收 public void setEvent(){ WritableMap params = Arguments.createMap(); params.putString("name", "Jack"); reactContext_ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(TestEventName, params); }
js端使用DeviceEventEmitter设置监听接收:
import { DeviceEventEmitter} from 'react-native';DeviceEventEmitter.addListener(CustomToastView.TestEventName,(res)=>{ console.log("我是事件监听"); console.log(res); });
大家也可以先看一下官方文档:http://reactnative.cn/docs/0.47/native-modules-android.html#content
遇到的问题:
1.在js端导出组件后使用的时候,报错:
解决方案:
在requireNativeComponent的第二个参数内,也就是描述组件属性的时候,在propTypes内,加入…View.propTypes:
因为,在这里我只描述了我规定的属性字段,RN其实自己会添加很多默认的属性,使用扩展符合并就可以了。
最后附上源码:https://github.com/1035901787/CustomRnView
- React Native封装Android原生控件
- react-native 在android封装原生listView
- React Native 控件封装
- React Native之原生UI组件封装---适配Android
- react native 学习笔记----封装Android的原生组件
- React-Native开发之原生模块封装(Android)升级版
- React Native之原生UI组件封装---适配Android
- React Native 原生模块封装、发布、调用 (Android)
- React Native 原生模块封装、发布、调用
- React Native 封装原生UI组件(iOS)
- React Native封装原生UI组件
- React-Native 自封装原生模块
- react native 密码控件 封装
- Android原生嵌入React Native
- React Native移植原生Android
- React Native封装Android原生UI和Android原生模块,并且集成腾讯云点播的Android SDK
- 【React Native开发】React Native移植原生Android项目(4)
- Android React Native使用原生模块
- Python中matplotlib画图
- 概率基础5-极限定理
- Ztree,异步逐级加载数据,连接数据库增删改,模糊搜索
- Case When的用法,简单小例子
- TCP最小传输单元和最大传输单元
- React Native封装Android原生控件
- Android 必知必会
- 如何实现按钮底部半透明,但是不影响按钮的字体正常显示
- java页面用js转换数据库中的datetime类型的时间为String类型显示
- 建表的同时建立约束
- MySQL CASE WHEN THEN
- SQL语句消除重复行(DISTINCT 的使用)
- 在虚拟机安装centos7
- [luogu-2678]noip2015day2-T1 跳石头 题解