React Native笔记(一):给rn提供android原生列表
作者:互联网
背景
react native官方提供的FlatList与原生RecyclerView相比:
- 仅创建可见区域的视图,两者是一致的。
- FlatList没有cell recycling,重用item view。
FlatList中将不可见的视图从内存中移除,但同时也会导致大量的视图重新创建以及垃圾回收。如果不断的创建视图,在列表滚动的过程中,内存占用量会不断增加。而原生的recyclerview因为能复用视图,所以在快速滑动的时候性能上影响不大。并且rn又支持封装原生组件给rn使用,于是产生了封装recyclerview给rn使用的想法。
步骤
- 创建列表item布局组件
关键点:列表item的rn布局如何传给RecyclerView的adapter
- rn的视图布局根节点为ReactRootView,它的底层是FrameLayout,因此可以在adapter的onCreateViewHolder中返回ReactRootView作为item的根视图。
- isRunning用于复用item的时候,可以直接setAppProperties更新ReactRootView的属性而不用重新startReactApplication加载。
public class RNItemView extends ReactRootView {
private final String cellModuleName;
private boolean isRunning = false;
public RNListItemView(Context context, String cellModuleName) {
super(context);
this.cellModuleName = cellModuleName;
}
private void startReactApp(Bundle bundle) {
isRunning = true;
ReactApplication app = (ReactApplication)getContext().getApplicationContext();
startReactApplication(app.getReactNativeHost().getReactInstanceManager(), cellModuleName, bundle);
}
public boolean isRunning() {
return isRunning;
}
}
其中cellModuleName为在rn index.js中注册的组件名字
2. 创建adapter
- 在onCreateViewHolder中将上一步创建的RNItemView作为item根视图传入
- 在onBindViewHolder中设置好item的布局参数
public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {
private List<Bundle> data;
private Context context;
private String cellModuleName;
public MyAdapter(Context context) {
this.context = context;
this.data = new ArrayList<>();
}
public void setData(List<Bundle> data){
this.data.clear();
this.data.addAll(data);
notifyDataSetChanged();
}
public void setCellModuleName(String cellModuleName){
this.cellModuleName = cellModuleName;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
RNItemView view = new RNItemView(context, cellModuleName);
return new ViewHolder(context, view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Bundle bundle = data.get(position);
RNItemView rnItemView = (RNItemView) holder.itemView;
LinearLayoutManager.LayoutParams params = (LinearLayoutManager.LayoutParams) rnItemView.getLayoutParams();
if (params == null){
params = new LinearLayoutManager.LayoutParams(bundle.getInt("pixelWidth"), bundle.getInt("pixelHeight"));
}else {
params.width = bundle.getInt("pixelWidth");
params.height = bundle.getInt("pixelHeight");
}
rnItemView.setLayoutParams(params);
if(!rnItemView.isRunning()){
rnItemView.startReactApp(bundle);
}else{
rnItemView.setAppProperties(bundle);
}
}
@Override
public int getItemCount() {
return data.size();
}
}
- 创建RecyclerView
- 将rn传过来的数据源解析元素尺寸,转换为pixel后传给adapter
public class RNRecyclerView extends RecyclerView {
MyAdapter adapter;
public RNRecyclerView(@NonNull Context context) {
super(context);
}
public RNRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
adapter = new MyAdapter();
LinearLayoutManager lm = new LinearLayoutManager(getContext());
setLayoutManager(lm);
setAdapter(adapter);
}
public void setCellModuleName(String cellModuleName){
adapter.setCellModuleName(cellModuleName);
}
public void setDataSource(ReadableArray dataSize){
List<Bundle> listData = new ArrayList<>();
for(int i = 0; i < newListSize; i++){
ReadableMap readableMap = dataSize.getMap(i);
Map<String, Object> map = readableMap.toHashMap();
Bundle b = changeMapToBundle(map);
b.putInt("pixelWidth", (int) PixelUtil.toPixelFromDIP(readableMap.getInt("width")));
b.putInt("pixelHeight", (int) PixelUtil.toPixelFromDIP(readableMap.getInt("height")));
listData.add(b);
}
adapter.setData(listData);
}
}
- 创建viewmanager
public class RNRecyclerViewManager extends SimpleViewManager<RNRecyclerView> {
@NonNull
@Override
public String getName() {
return "RNRecyclerView";
}
@NonNull
@Override
protected RNRecyclerView createViewInstance(@NonNull ThemedReactContext reactContext) {
return new RNRecyclerView(reactContext);
}
@ReactProp(name = "cellModuleName")
public void setCellModuleName(RNRecyclerView view, String cellModuleName){
view.setCellModuleName(cellModuleName);
}
@ReactProp(name = "dataSource")
public void setDataSource(RNRecyclerView view, ReadableArray array){
view.setDataSource(array);
}
}
- 创建rn组件,数据源元素最好带上item的尺寸
export interface MyData<T> {
width: number,
height: number,
data: T
}
interface Props<T> {
style?: StyleProp<ViewStyle>
dataSource?: MyData<T>[]
cellItemName: string
}
const NativeRNRecyclerView = requireNativeComponent('RNRecyclerView')
export default class RNRecyclerView extends React.Component<Prop<T>> {
constructor(props: Prop<T>) {
super(props);
}
render(){
return (
<NativeRNRecyclerView
{...this.props}
>
</NativeRNRecyclerView>
)
}
}
/*
* 测试代码
*/
const {width} = Dimensions.get('window')
export default class TestRNRecyclerView extends React.Component<any>{
constructor(props: any) {
super(props);
this.state = {
dataSource: [],
}
}
componentDidMount(){
//构造数据
let dataSet: MyData<string>[] = []
for(let i = 0; i < 30; i++){
this.dataSet.push({widht: width, height: 100, data:'row'+i});
}
this.setState({
dataSource: dataSet
})
}
render() {
return (
<View style={{
height: "100%"
}}>
<RNRecyclerView
style={{
width: "100%",
height: "100%"
}}
cellModuleName={"MyItemView"}
dataSource={this.state.dataSource}
/>
</View>
);
}
}
export default class MyItemView extends React.Component<MyData<string>>{
constructor(props: MyData<string>){
super(props)
}
render() {
if (this.props.data == undefined){
return null
}
//dataSet数据
let info = this.props.data;
return (
<View>
<Text style={{
color: "#FF0000"
}}>
{info}</Text>
</View>
)
}
}
//index.js
AppRegistry.registerComponent('MyItemView', () => MyItemView);
- MyItemView在index.js中注册好,名称会通过cellModuleName属性传给原生,等待adapter创建加载,而传给RNRecyclerView的dataSource数组元素会通过props回传给MyItemView组件
标签:RNRecyclerView,public,React,context,props,rn,cellModuleName,data,android 来源: https://blog.csdn.net/weixin_40855673/article/details/123621834