React-Native系列Android自定义原生UI组件
来源:互联网 发布:安徽博微智能电气知乎 编辑:程序博客网 时间:2024/06/06 14:15
由于官方的Android原生UI组件解释的并不是很完整,根据个人的不断摸索,终于成功完成原生组件的制作,所以写下这篇文章作为记录,也给让小白们少走些弯路。
我这里通过讲解制作一个绘圆组件的流程,来学习制作android原生UI组件。这个绘圆组件并没有实际的使用价值,只是为了更容易的了解android原生UI组件的制作过程。好了废话不多说,现在开始吧。
- react-native版本:0.33.0
首先初始化react-native项目,最好能弄个VPN
react-native init AndroidNativeModule
初次build android项目,先打开虚拟机或连接手机。
react-native run-android
项目的创建就讲到这,详细的项目创建和排错请自行百度。现在我们用Android Stuido进入android项目。
创建基本的UI组件框架,这里组件名称严格更具功能进行命名,为了看的更清楚进行了一些打包
- CircleManager.java CIrcle原生组件管理器,实现JS和JAVA信息传递
- CircleView.java Circle原生组件
- MainPackage.java 自定义组件注册包
接下来给创建好的java添加基本结构,然后在后面更具需要添加细节功能
- CircleView.java 基础结构
package com.androidnativemodule.module.circle;import android.content.Context;import android.view.View;/** * 圆形组件组件基础类 */public class CircleView extends View { public CircleView(Context context) { super(context); }}
UI组件继承于View类,这里没有加什么功能,就创建一个基本的类
- CircleManager.java
package com.androidnativemodule.module.circle;import com.facebook.react.uimanager.SimpleViewManager;import com.facebook.react.uimanager.ThemedReactContext;/** * 圆形组件基础类管理器 */public class CircleManager extends SimpleViewManager<CircleView> { /** * 设置js引用名 * @return String */ @Override public String getName() { return "MCircle"; } /** * 创建UI组件实例 * @param reactContext * @return CircleView */ @Override protected CircleView createViewInstance(ThemedReactContext reactContext) { return new CircleView(reactContext); }}
所有的组件管理器需要继承SimpleViewManager类,后面加上自己定义的组件基础类,下面2个方法是SimpleViewManager类的必须实现的方法,记住getName()返回的名字要和JS里的应用名进行统一。
- MainPackge.java
package com.androidnativemodule;import com.androidnativemodule.module.circle.CircleManager;import com.facebook.react.ReactPackage;import com.facebook.react.bridge.JavaScriptModule;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;/** * 自定义组件模块注册类 */public class MainPackage implements ReactPackage { /** * 创建原生模块 * @param reactContext * @return */ @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } /** * 创建原生UI组件控制器 * @param reactContext * @return */ @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new CircleManager() ); }}
这个是注册类,实现ReactPackage接口,可以想自己设计的组件统一写在这个类中,然后一起在Application中注册,注意:返回空值需要返回Collections.emptyList()
。它还可以注册原生模块,这个官方有详细的讲解,地址如下:http://facebook.github.io/react-native/docs/native-modules-android.html
注册类写好后,还需要将这个类加载进Application中,我们在通过MainApplication中将其加入进去。
- MainApplication.java
package com.androidnativemodule;import android.app.Application;import android.util.Log;import com.facebook.react.ReactApplication;import com.facebook.react.ReactInstanceManager;import com.facebook.react.ReactNativeHost;import com.facebook.react.ReactPackage;import com.facebook.react.shell.MainReactPackage;import java.util.Arrays;import java.util.List;public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new MainPackage() // 在这里加载我们自己的注册类 ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; }}
到这里我们的自定义UI组件框架基本完成,我们可以run一下看看,如果没有效果,可以尝试重新react-native run-android
下。
在Android Monitor中可以看到已经加载了我们的CircleModule,只有有没我们JS并没有实例话他,所以Could not find generated setter for class com.androidnativemodule.module.circle.CircleManager
。
接下来我们给我们的原生UI组件加上功能。
- CircleView.java
package com.androidnativemodule.module.circle;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.util.Log;import android.view.View;/** * 圆形组件组件基础类 */public class CircleView extends View { private final String TAG = "CircleView"; private Paint mPaint; // 画笔 public CircleView(Context context) { super(context); mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(100, 100, 100, mPaint); // 画一个半径为100px的圆 Log.d(TAG, "绘图"); }}
这里我先在CircleView内写死代码,看看这个原生UI到底能不能在JS中使用
现在我们来到react-native项目,我们先定制一个Circle组件的JS接口,方便其他组件调用。
- 创建Circle.js
import { PropTypes } from 'react';import { requireNativeComponent, View } from 'react-native';const MCircle = requireNativeComponent('MCircle', { propTypes: { ...View.propTypes // 包含默认的View的属性 },});export default MCircle;
使用requireNativeComponent根据先前在管理器中定义好的组件名引用原生组件,由于我们还没创建接口,所以这个组件暂时只有父类View的接口。
现在我们在index.android.js中实例化组件看看效果
- index.android.js
'use strict';import React, { Component } from 'react';import { AppRegistry, StyleSheet, Text, View} from 'react-native';import Circle from './Circle';class AndroidNativeModule extends Component { render() { return ( <View style={styles.container}> <Circle style={{width: 100, height: 100}} /> </View> ); }}const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }});AppRegistry.registerComponent('AndroidNativeModule', () => AndroidNativeModule);
效果图:
可以看到成功使用Android canvas 画了一个圆
现在我们给他加一些接口,从而实现JS和JAVA的通讯,直接在JS中更改组件样式。
- CircleView.java
package com.androidnativemodule.module.circle;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.util.Log;import android.view.View;import com.facebook.react.uimanager.PixelUtil;/** * 圆形组件组件基础类 */public class CircleView extends View { private final String TAG = "CircleView"; private Paint mPaint; // 画笔 private float mRadius; // 圆的半径 public CircleView(Context context) { super(context); mPaint = new Paint(); } /** * 设置圆的背景色 * @param color */ public void setColor(Integer color) { mPaint.setColor(color); // 设置画笔颜色 invalidate(); // 更新画板 } /** * 设置圆的半径 * @param radius */ public void setRadius(Integer radius) { /** * 由于JS传过的数字是dip单位,需要转换为实际像素 * 使用com.facebook.react.uimanager包中的PixelUtil,进行转换 */ mRadius = PixelUtil.toPixelFromDIP(radius); invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); // 画一个半径为100px的圆 Log.d(TAG, "绘图"); }}
这里添加了2个接口,实现对圆的大小和颜色更改,还使用了PixelUtil
实现像素的转换
- CircleManager.java
package com.androidnativemodule.module.circle;import com.facebook.react.uimanager.SimpleViewManager;import com.facebook.react.uimanager.ThemedReactContext;import com.facebook.react.uimanager.annotations.ReactProp;/** * 圆形组件基础类管理器 */public class CircleManager extends SimpleViewManager<CircleView> { /** * 设置js引用名 * @return String */ @Override public String getName() { return "MCircle"; } /** * 创建UI组件实例 * @param reactContext * @return CircleView */ @Override protected CircleView createViewInstance(ThemedReactContext reactContext) { return new CircleView(reactContext); } /** * 传输背景色参数 * @param view * @param color */ @ReactProp(name = "color") public void setColor(CircleView view, Integer color) { view.setColor(color); } /** * 传输半径参数 * @param view * @param radius */ @ReactProp(name = "radius") public void setRadius(CircleView view, Integer radius) { view.setRadius(radius); }}
管理器中引用接口,将参数传输过去
现在我们的CircleModule已经完成了,然后我们修改下Circle组件JS接口,实现接口使用。
- Circle.js
'use strict';import React, { Component, PropTypes } from 'react';import { View, requireNativeComponent, processColor // 字符Color转换为数字} from 'react-native';const MCircle = requireNativeComponent('MCircle', { propTypes: { color: PropTypes.number, radius: PropTypes.number, ...View.propTypes // 包含默认的View的属性 },});class Circle extends Component { static propTypes = { radius: PropTypes.number, color: PropTypes.string, // 这里传过来的是string ...View.propTypes // 包含默认的View的属性 } render() { const { style, radius, color } = this.props; return ( <MCircle style={style} radius={radius} color={processColor(color)} /> ); }}module.exports = Circle;
由于color使用的是String,我们可以用react-native的processColor将其转换为数字,从而可以让java识别出颜色,为了方便使用,所以我这边重写创建了Component,作为中间组件,对color进行转换。
然后我的就可以通过Circle.js使用CircleModule了,例如:
<Circle style={{width: 100, height: 100}} color="#25c5f7" radius={50}/>
效果图:
到此Android自定义原生UI组件CircleModule的设计就结束了,如果有错误的地方,大家可以指出来反馈给我,也希望大家可以将自己的react-native开发心得分享出来,大家一起来学习。
- React-Native系列Android自定义原生UI组件
- Android React Native使用原生UI组件
- 【稀饭】react native 实战系列教程之自定义原生UI组件
- React Native之原生UI组件封装---适配Android
- React Native之原生UI组件封装---适配Android
- React Native十五:原生UI组件
- React Native使用指南-原生UI组件
- React Native 封装原生UI组件(iOS)
- React Native封装原生UI组件
- React Native使用原生UI组件
- React Native 使用原生 UI 组件
- React Native调用原生UI组件
- react native 调用原生UI组件
- React Native调用Android原生组件
- React-Native系列Android——自定义View组件开发
- React Native 添加自定义UI组件
- React Native 原生UI组件的基本使用
- React-native 调用原生组件
- S5PV210时钟详解
- css兼容性问题
- 环境变量配置(JDK,ADB)
- **UML** UML建模工具的理论介绍
- Python调用微软语音识别
- React-Native系列Android自定义原生UI组件
- Vim操作总结
- JavaScript Dom 编程艺术 笔记
- jquery随笔
- Metrics & keylines - Layout - Google design guidelines
- 缓存淘汰算法--LRU算法
- UE4联机烘焙
- 皇冠书籍,小雷推荐
- 设计模式之工厂模式之单例模式