使用ViewGroupManager和FrameLayout开发RN安卓原生组件失败求助
问题描述
我正在为React Native开发安卓原生UI组件,因要制作播放器组件,参考了react-native-video项目并查阅了React Native官方文档。编写了一段渲染TextView的简单Java代码后,运行应用发现安卓端的TextView组件并未在屏幕上显示。请问如何通过ViewGroupManager和FrameLayout让该组件正常显示?
现有代码
MyPackage implements ReactPackage
public class MyPackage implements ReactPackage { @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new ReactTextViewManager(reactContext) ); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); return modules; } }
ReactTextViewManager extends ViewGroupManager
我使用ViewGroupManager是因为react-native-video项目将其用作视图管理器。
public class ReactTextViewManager extends ViewGroupManager<ReactTextView> { public static final String REACT_CLASS = "RCTTextView"; private static final String TAG = "ReactTextViewManager"; ReactApplicationContext mCallerContext; public ReactTextViewManager(ReactApplicationContext context) { mCallerContext = context; } @NonNull @Override public String getName() { return REACT_CLASS; } @NonNull @Override public ReactTextView createViewInstance(@NonNull ThemedReactContext context) { return new ReactTextView(context); } @ReactProp(name = "text") public void setText(ReactTextView view, String text) { Log.i(TAG, "ReactProp: " + text); view.setText(text); } }
ReactTextView extends FrameLayout
我使用FrameLayout是因为react-native-video项目将其用作视图。
public class ReactTextView extends FrameLayout { private final TextView textView; public ReactTextView(ThemedReactContext context) { super(context); textView = new TextView(context); textView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); addView(textView); } public void setText(String text) { if (textView != null) { textView.setText(text); } } }
注册与使用
MainApplication
public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new DefaultReactNativeHost(this) { // ... @Override protected List<ReactPackage> getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") List<ReactPackage> packages = new PackageList(this).getPackages(); // 无法自动链接的包可在此手动添加,例如: // packages.add(new MyReactNativePackage()); packages.add(new MyPackage()); return packages; } //... }
React Native端代码
import { HostComponent, requireNativeComponent } from 'react-native'; interface TextViewProps { text?: string; } export type VideoComponentType = HostComponent<TextViewProps>; export default requireNativeComponent<TextViewProps>( 'RCTTextView', ) as VideoComponentType;
以及App组件:
import React from 'react'; import { SafeAreaView, StyleSheet, Text } from 'react-native'; import TextView from './components/TextView'; function App(): JSX.Element { return ( <SafeAreaView style={styles.container}> <Text>Top</Text> <TextView text="Hello World" /> <Text>Bottom</Text> </SafeAreaView> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#dedede', }, }); export default App;
解决方案
问题核心是React Native中基于ViewGroupManager的组件默认不会自动测量自身尺寸,导致你的FrameLayout宽高为0,内部TextView自然无法显示。需要通过重写测量方法来指定组件尺寸,具体修改如下:
1. 修改ReactTextView类,重写onMeasure方法
在ReactTextView中添加onMeasure方法,让FrameLayout根据内部TextView的尺寸来设置自身大小:
public class ReactTextView extends FrameLayout { private final TextView textView; public ReactTextView(ThemedReactContext context) { super(context); textView = new TextView(context); textView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); addView(textView); } public void setText(String text) { if (textView != null) { textView.setText(text); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 先测量内部TextView的尺寸 textView.measure(widthMeasureSpec, heightMeasureSpec); // 将当前FrameLayout的尺寸设置为TextView的测量结果 setMeasuredDimension(textView.getMeasuredWidth(), textView.getMeasuredHeight()); } }
2. (可选)在React Native端添加样式约束
如果希望组件能响应React Native的样式设置,可以给TextView组件添加样式属性,比如指定宽高或flex布局:
<TextView text="Hello World" style={{width: '100%', padding: 16}} />
完成上述修改后,重新编译运行安卓项目,就能看到TextView正常显示了。
内容的提问来源于stack exchange,提问作者junep
相关产品推荐
相关产品推荐

