React Native学习之RN调用原生UI组件
React Native已经封装了大部分最常见的组件,譬如ScrollView和TextInput,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
首先准备好原生UI组件:自定义View,第三方SDK,网络依赖,jar包
KenBurnsView
KenBurnsView
组件可以显示图片的一部分,然后通过改变显示位置来显示其他部分,配上合适的图片,可以产生一种在飞机上往下看的视觉效果(俯瞰图)。
KenBurnsView
:Android library that provides an extension to ImageView that creates an immersive experience by animating its drawable using the Ken Burns Effect.
GitHub:https://github.com/flavioarfaria/KenBurnsView
配置 build.gradle
dependencies {
compile 'com.flaviofaria:kenburnsview:1.0.7'
}
点击同步执行 Gradle Build
暴露原生视图给React Native的步骤:
创建一个ViewManager的子类
实现getName
和createViewInstance
方法
- getName 是 React Native 端能够识别的组件名称
- createViewInstance 是组件初始化方法
public class KenBurnsViewManager extends SimpleViewManager<KenBurnsView> {
private ThemedReactContext context;
@Override
public String getName() {
return "KenBurnsView";
}
@Override
protected KenBurnsView createViewInstance(ThemedReactContext reactContext) {
return null;
}
}
使用@ReactProp
(或@ReactPropGroup
)注解
要导出给JavaScript使用的属性,需要申明带有@ReactProp
(或 @ReactPropGroup
)注解的设置方法。方法的第一个参数是要修改属性的视图实例,第二个参数是要设置的属性值。方法的返回值类型必须为 void,而且访问控制必须被声明为 public。
//暴露属性
@ReactProp(name = "imgSource")
public void setSource(KenBurnsView view, String source){
try {
InputStream inputStream = context.getAssets().open(source);
Drawable drawable = Drawable.createFromStream(inputStream, null);
view.setImageDrawable(drawable);
} catch (IOException e) {
e.printStackTrace();
}
}
JavaScript 所得知的属性类型会由该方法第二个参数的类型来自动决定。支持的类型有:boolean
, int
, float
, double
, String
, Boolean
, Integer
, ReadableArray
, ReadableMap
。
@ReactProp
注解必须包含一个字符串类型的参数 name。这个参数指定了对应属性在 JavaScript 端的名称。
除了 name,@ReactProp
注解还接受这些可选参数:defaultBoolean
, defaultInt
, defaultFloat
。这些参数必须是对应的基础类型的值(也就是 boolean, int, float),这些值会被传递给 setter 方法,以免 JavaScript 端某些情况下在组件中移除了对应的属性。注意这个“默认”值只对基本类型生效,对于其他的类型而言,当对应的属性删除时,null 会作为默认值提供给方法。
使用@ReactPropGroup
来注解的设置方法和@ReactProp
不同。请参见@ReactPropGroup
注解类源代码中的文档来获取更多详情。
注意:在ReactJS中,每修改一个属性都会引发一次对设置方法的调用。有一种修改情况是,移除掉之前设置的属性,在这种情况下设置方法也一样会被调用,并且“默认”值会被作为参数提供(对于基础类型来说可以通过 defaultBoolean, defaultFloat 等 @ReactProp 的属性提供),而对于复杂类型来说参数则会设置为 null)。
创建一个ReactPackage的子类,把这个视图管理类注册到应用程序包的createViewManagers里
public class MyReactPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new KenBurnsViewManager()
);
}
}
在MainAppcation 中的 getPackages 方法中添加 ReactPackage 的子类对象
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(), new MyReactPackage()
);
}
实现 React Native 端的 JavaScript 模块
组件接口
import React, { Component,PropTypes } from 'react';
import {
requireNativeComponent,
View
} from 'react-native';
let iface={
name:'KenBurnsView',
propTypes:{
imgSource:PropTypes.string,
//imgSource:PropTypes.string.isRequired,
...View.propTypes
},
};
module.exports = requireNativeComponent('KenBurnsView', iface);
requireNativeComponent
通常接受两个参数,第一个参数是原生视图的名字(JAVA层KenBurnsViewManager$getName
的值),而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的 name,用于在调试信息中显示;组件接口还必须声明 propTypes 字段,用来对应到原生视图上。这个propTypes
还可以用来检查用户使用 View 的方式是否正确,View.propTypes
表示包含View的所有属性。最后通过module.exports
导出提供给其他组件使用。
注意:如果你还需要一个 JavaScript 组件来做一些除了指定
name
和propTypes
以外的事情,譬如事件处理,可以把原生组件使用一个普通的 React 组件封装。在这种情况下,requireNativeComponent 的第二个参数变为用于封装的组件。注意:和原生模块不同,原生视图的前缀RCT不会被自动去掉。
组件调用
import KenBurnsView from './KenBurnsView.js';
<KenBurnsView
imgSource='shanghai.jpg'
style={{width:200, height:300}}
/>
源码
KenBurnsViewManager.java
public class KenBurnsViewManager extends SimpleViewManager<KenBurnsView> {
private ThemedReactContext context;
@Override
public String getName() {
return "KenBurnsView";
}
@Override
protected KenBurnsView createViewInstance(ThemedReactContext reactContext) {
context = reactContext;
KenBurnsView kenBurnsView = new KenBurnsView(context);
try {
InputStream inputStream = context.getAssets().open("shanghai.jpg");
Drawable drawable = Drawable.createFromStream(inputStream, null);
kenBurnsView.setImageDrawable(drawable);
} catch (IOException e) {
e.printStackTrace();
}
return kenBurnsView;
}
//暴露属性
@ReactProp(name = "imgSource")
public void setSource(KenBurnsView view, String source){
try {
InputStream inputStream = context.getAssets().open(source);
Drawable drawable = Drawable.createFromStream(inputStream, null);
view.setImageDrawable(drawable);
} catch (IOException e) {
e.printStackTrace();
}
}
}
MyReactPackage.java
public class MyReactPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new KenBurnsViewManager()
);
}
}
MainApplication.java
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(), new MyReactPackage()
);
}
KenBurnsView.js
import React, { Component,PropTypes } from 'react';
import {
requireNativeComponent,
View
} from 'react-native';
let iface={
name:'KenBurnsView',
propTypes:{
imgSource:PropTypes.string,
...View.propTypes
},
};
module.exports = requireNativeComponent('KenBurnsView', iface);
index.android.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import KenBurnsView from './KenBurnsView.js';
class RNAPP extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.welcome}>
React Native混合原生开发
</Text>
<Text style={styles.instructions}>
Powered by rnapp.cc
</Text>
<KenBurnsView
imgSource='shanghai.jpg'
style={{width:200, height:300}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
btn: {
marginTop: 20,
marginLeft: 10,
marginRight: 10,
width: 260,
height: 35,
backgroundColor: '#3BC1FF',
color: '#fff',
lineHeight: 24,
fontWeight: 'bold',
textAlign: 'center',
textAlignVertical:'center'
},
});
AppRegistry.registerComponent('RNAPP', () => RNAPP);
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/react-native-learning-rn-calling-native-ui-components/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论