ReactNative 调用Android 原生(二)——原生组件
原创
©著作权归作者所有:来自51CTO博客作者是丹凤呀的原创作品,请联系作者获取转载授权,否则将追究法律责任
ReactNative 调用Android 原生(一)——原生模块(一)
ReactNative 调用Android 原生(一)——原生模块(二):
这是demo链接:https://github.com/danfengfirst/VisitAndroid 先说下我遇到的坑:
原本学完React Native调用原生模块我觉得挺顺利的,也挺容易理解的,觉得调用Android原生组件也是不成问题,应该挺快的,结果React Native 调原生组件一直不显示,在网上找了好多文章对比看,觉得自己代码、步骤都没有问题,调用控件不显示的原因文章末尾跟代码的注释里面我都将说明,免得有跟我一样入坑的!
步骤
1、继承SimpleViewManager
2、实现ReactPackage
3、向MainApplication添加ReactPackage
4、RN中导出View
5、使用导出的View
使用
如果你看过ReactNative 调用Android 原生(一)——原生模块(一)、(二)就很熟悉这个流程了,下面这个Demo是个倒计时的效果
1、继承SimpleViewManager,
(1)getName()返回的名字在RN中将被用到
(2) @ReactProp(name = “start”) 中@ReactProp注解用于定义方法,name = "start"中的start就是RN中导出的View可以使用的属性名
public class TestUI extends SimpleViewManager<TimerView> {
@Override
public String getName() {
return "TimerView";
}
@Override
protected TimerView createViewInstance(ThemedReactContext reactContext) {
return new TimerView(reactContext);
}
@ReactProp(name = "start")
public void startTimer(TimerView timerView, Integer totalCount) {
timerView.startTimer(totalCount);
}
}
补充:
public class TimerView extends LinearLayout {
private Timer mTimer;
private TimerTask mTimerTask;
private TextView mTimerTv;
private Context mContext;
private int mCount;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTimerTv.setText(mCount + "");
int w = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY);
int h = MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY);
measure(
w,
h);
layout(getLeft(), getTop(), getRight(), getBottom());
}
};
public TimerView(Context context) {
this(context,null);
}
public TimerView(Context context, @Nullable AttributeSet attrs) {
super(context);
init(context);
}
private void init(Context context) {
mContext = context;
//布局的话随便加载
View view = LayoutInflater.from(context).inflate(R.layout.timer_view, this);
view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
mTimerTv = view.findViewById(R.id.timer_tv);
mTimerTv.setText(10 + "");
}
//调用该方法,开始倒计时
public void startTimer(int totalcount) {
mCount = totalcount;
mTimerTv.setText(totalcount + "");
mTimer = new Timer();
mTimerTask = new TimerTask() {
@Override
public void run() {
if (mCount >= 0) {
--mCount;
mHandler.sendEmptyMessage(0);
} else {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
}
};
mTimer.schedule(mTimerTask, 0, 1000);
}
}
2、实现ReactPackage
public class TestPackages implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> nativeModules = new ArrayList<>();
nativeModules.add(new TestModules(reactContext));
return nativeModules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new TestUI()
);
}
}
3、向MainApplication添加ReactPackage
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new TestPackages()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
4、RN中导出View
这里就是坑了,必须写style并设置宽高,否则不显示
属性名:start对应上面的
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {
requireNativeComponent,
View
} from 'react-native';
//Android 原生View 映射成AndroidTimerView,导出为NativeTimerView
const AndroidTimerView = requireNativeComponent('TimerView', NativeTimerView);
export default class NativeTimerView extends Component<Props> {
static propTypes = {
stimer: PropTypes.number,
};
render() {
return <AndroidTimerView
style={{width: 100, height: 50, borderRadius: 20}}
start={this.props.stimer}
/>
}
}
5、使用导出的View
如果你在第4步中没有设置style 在这里对NativeTimerView设置style的宽高,运行后仍然会什么都不显示,因此必须在第4步中设置宽高
export default class App extends Component<Props> {
constructor() {
super();
this.state = {
name: 'To get started, edit App.js',
sendEvent: 'Send Event'
}
}
toast = () => {
let obj = {
id: 1,
name: "xiaohong"
};
NativeModules.TestModules.Toasts(obj);
};
toastFinishCallback = () => {
NativeModules.TestModules.ToastFinished("调用了原生并带有回调", (result) => {
this.setState({
name: result.name
});
});
};
sendEvent = () => {
NativeModules.TestModules.sendEvent();
};
componentWillMount() {
DeviceEventEmitter.addListener('sendEvent', (e: Event) => {
this.setState({
sendEvent: e.name
});
})
};
startActivity = () => {
NativeModules.TestModules.startActivity();
};
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}
onPress={this.toast}
>Welcome to React Native!</Text>
<Text style={styles.instructions}
onPress={this.toastFinishCallback}
>{this.state.name}</Text>
<Text style={styles.instructions}
onPress={this.sendEvent}
>{this.state.sendEvent}</Text>
<Text
style={styles.instructions}
onPress={this.startActivity}
>点击开启activity</Text>
<NativeTimerView
style={{width: 100, height: 50, borderRadius: 20}}
stimer={60}
/>
</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,
},
});
总结
我的之前显示不出来就是因为我在第5步设置的宽高,而没有在第4步设置宽高,结果就一直显示不出来,希望不要有人再犯我这样的错误了。