ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

React Native笔记(一):给rn提供android原生列表

2022-03-21 09:59:00  阅读:260  来源: 互联网

标签:RNRecyclerView public React context props rn cellModuleName data android


背景

react native官方提供的FlatList与原生RecyclerView相比:

  • 仅创建可见区域的视图,两者是一致的。
  • FlatList没有cell recycling,重用item view。

FlatList中将不可见的视图从内存中移除,但同时也会导致大量的视图重新创建以及垃圾回收。如果不断的创建视图,在列表滚动的过程中,内存占用量会不断增加。而原生的recyclerview因为能复用视图,所以在快速滑动的时候性能上影响不大。并且rn又支持封装原生组件给rn使用,于是产生了封装recyclerview给rn使用的想法。

步骤

  1. 创建列表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();
    }

}
  1. 创建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);
	}
}
  1. 创建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);
    }
}
  1. 创建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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有