React Native 系列(七)

前言

本系列是基于React Native版本号0.44.3写的。几乎所有的App都使用了ListView这种组件,这篇文章将学习RNListView的平铺样式和分组样式。

ListView平铺样式

  • ListView内部是通过ListViewDataSource这个对象显示数据的,因此使用ListView的时候需要创建一个ListViewDataSource对象。
  • ListViewDataSource构造方法创建对象的时候可以选择性出入4个参数,描述怎么提取cell,怎么刷新cell
  • 这些参数都是函数,当产生对应事件的时候,会自动调用对应函数
    构造函数可以接收以下四种参数(都是函数):
    
    getRowData(dataBlob, sectionID, rowID); // 怎么获取行数据
    getSectionHeaderData(dataBlob, sectionID); // 获取没组头数据
    rowHasChanged(prevRowData, nextRowData); // 决定什么情况行数据才发生改变,当行数据发生改变,就会绘制下一行
    sectionHeaderHasChanged(prevSectionData, nextSectionData); // 决定什么情况头部数据才会发生改变,当头部数据发生改变,就会绘制下一个组
  • ListViewDataSourceListView组件提供高性能的数据处理和访问。我们需要调用clone方法从原始输入数据中抽取数据来创建ListViewDataSource对象。
  • 要更新datasource中的数据,请(每次都重新)调用cloneWithRows方法(如果用到了section,则对应cloneWithRowsAndSections方法)clone方法会自动提取新数据并进行逐行对比(使用rowHasChanged方法中的策略),这样ListView就知道哪些行需要重新渲染了。

平铺样式使用步骤

  1. 创建数据源

    • 因为改变数据的时候需要刷新界面,因此可以利用setState
    • 获取ListViewDataSource使用ListView.DataSource
    • ListViewDataSource构造方法:决定ListView怎么去处理数据,需要传入一个对象,这个对象有四个可选属性,都是方法。
    • 初始化ListViewDataSource的时候,如果不需要修改提取数据的方式,只需要实现rowHasChanged,告诉什么时候刷新下一行
    • 默认ListViewDataSource有提取数据方式,可以使用默认提取方式。
    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    }
  2. 给数据源设置数据
    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.state = {
            dataSource: ds.cloneWithRows([‘row1‘, ‘row2‘])
        }
    }
  3. 实现数据源方法,确定cell
    • 这个方法会自动传入四个参数(rowData, sectionID, rowID, highlightRow)
    • rowData: 行数据
    • sectionID: 当前行所在的组id
    • rowID: 当前行所在的行id
    • highlightRow: 高亮函数
    render() {
        return (
            <ListView style={{marginTop: 20}}
                      dataSource={this.state.dataSource}
                      renderRow={this._renderRow.bind(this)}
            />
        );
    }
    
    _renderRow(rowData, sectionID, rowID, highlightRow){
        return (
            <View>
                <Text>{rowData}</Text>
            </View>
        );
    }

ListView分割线

运行上面的代码,你会发现ListView没有分割线,我们可以添加分割线:

render() {
    return (
        <ListView style={{marginTop: 20}}
                  dataSource={this.state.dataSource}
                  renderRow={this._renderRow.bind(this)}
        renderSeparator={this._renderSeparator.bind(this)}
        />
    );
}

_renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
    return (
        <View style={{height:1,backgroundColor:‘black‘}}>

        </View>
    )
}

ListView头部视图

_renderHeader(){
    return (
        <View style={[{height:30}, {backgroundColor:‘red‘},{justifyContent: ‘center‘}]}>
            <Text style={[{textAlign: ‘center‘}]}>头部视图</Text>
        </View>
    );
}

效果图:

ListView尾部视图

_renderFooter(){
    return (
        <View style={[{height: 30}, {backgroundColor: ‘red‘}, {justifyContent:‘center‘}]}>
            <Text style={{textAlign: `center`}}>尾部视图</Text>
        </View>
    )
}

效果图:

ListView点击cell高亮

_renderRow(rowData, sectionID, rowID, highlightRow){
    return (
        <TouchableOpacity onPress={()=>{
            AlertIOS.alert(rowID)
            highlightRow(sectionID, rowID)
        }}>
            <View style={{height: 40}}>
                <Text>{rowData}</Text>
            </View>
        </TouchableOpacity>
    );
}

注意:需要导入TouchableOpacityAlertIOS

ListView分组样式

有时候我们会遇到ListView分组样式,比如中国有多少个省,然后每个省又有多少个城市。
要想明白ListView是如何分组的,就需要知道ListView底层是如何获取组数据,行数据。

ListView分组原理

  • ListView默认支持3种格式的数据,只要按照这3种格式处理数据,就会自动获取数据,从而达到分组样式
默认的3种格式的数据:

// 格式一
[[row_0, row_1,...],[row_0, row_1,...],...]

// 格式二
{sectionID_0:{rowID_0, rowID_1, rowID_2, ...}, ...}

// 格式三
{sectionID_0:[rowID_0, rowID_1, ...], ...}

实现ListView分组样式步骤

  1. 创建数据源

    var dataSource = new ListView.DataSource({
        rowHasChanged:(r1,r2)=>r1 !== r2,
        sectionHeaderHasChanged:(s1,s2)=>s1 !== s2
    });
  2. 设置数据
    • 不分组使用: cloneWithRows()
    • 分组使用: cloneWithRowsAndSections()
    this.state = {
        dataSource: ds.cloneWithRowsAndSections(Data)
    }
  3. 渲染ListView

代码演练

这个例子我们使用了本地假数据,创建一个Data.json文件,它看起来是这样:

[
  ["section0-row0","section0-row1","section0-row2","section0-row3"],
  ["section1-row0","section1-row1","section1-row2","section1-row3"],
  ["section2-row0","section2-row1","section2-row2","section2-row3"],
  ["section3-row0","section3-row1","section3-row2","section3-row3"],
  ["section4-row0","section4-row1","section4-row2","section4-row3"],
  ["section5-row0","section5-row1","section5-row2","section5-row3"]
]

我们在index.ios.js里面引用Data.json

var Data = require(‘./Data.json‘)

然后就按照上述 实现ListView分组样式 步骤写:

var Data = require(‘./Data.json‘)

// 主组件
export default class RNDemoOne extends Component {
    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        var ds = new ListView.DataSource({
            rowHasChanged: (r1, r2) => r1 !== r2,
            sectionHeaderHasChanged: (s1, s2) => s1 !== s2
        });

        this.state = {
            dataSource: ds.cloneWithRowsAndSections(Data)
        }
    }

    render() {
        return (
            <ListView style={{marginTop: 20}}
                dataSource={this.state.dataSource}
                renderRow={this._renderRow.bind(this)}
          renderSeparator={this._renderSeparator.bind(this)}          renderSectionHeader={this._renderSectionHeader.bind(this)}
            />
        );
    }

    _renderSectionHeader(sectionData, sectionID){
        return (
            <View style={[{height: 40}, {backgroundColor:‘red‘}]}>
                <View style={[{flex:1}, {justifyContent: ‘center‘}]}>
                    <Text style={{paddingLeft: 10}}>{sectionID}</Text>
                </View>
            </View>
        )
    }

    _renderRow(rowData, sectionID, rowID, highlightRow){
        return (
            <TouchableOpacity onPress={()=>{
                AlertIOS.alert(rowID)
                highlightRow(sectionID, rowID)
            }}>
                <View style={{height: 40}}>
                    <Text>{rowData}</Text>
                </View>
            </TouchableOpacity>
        );
    }

    _renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
        return (
            <View style={{height:1,backgroundColor:‘black‘}}>

            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
});

致谢

如果发现有错误的地方,欢迎各位指出,谢谢!

时间: 2024-08-10 15:10:10

React Native 系列(七)的相关文章

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来 课程持续更新中..... 我是RichardCao,现任新美大酒店旅游事业群的Android Developer.如果你也有兴趣录制RN视频,请加入下面QQ群找我. 下载地址:https://pan.baidu.com/s/1c1XmE56 密码:shhw 首发地址:菜鸟窝-ReactNative学习板块 交流QQ群:576089067 课程目录:菜鸟窝React Native 系列教程

【REACT NATIVE 系列教程之十三】利用LISTVIEW与TEXTINPUT制作聊天/对话框&&获取组件实例常用的两种方式

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2346.html 本篇Himi来利用ListView和TextInput这两种组件实现对话.聊天框. 首先需要准备的有几点:(组件的学习就不赘述了,简单且官方有文档) 1. 学习下 ListView: 官方示例:http://reactnative.cn/docs/0.27/tutorial.html#content

【REACT NATIVE 系列教程之二】创建自定义组件&&导入与使用示例

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2219.html 在上一篇  [REACT NATIVE 系列教程之一]触摸事件的两种形式与四种TOUCHABLE组件详解 中的最后介绍了如何使用Touchable的四种组件进行监听触摸事件.  那么紧接着我们利用Touchable来包装一个带图片的Button组件,且设计成可接受很多自定义参数. 一:创建我们自定义

【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)与IOS(OBJECT-C)交互通信

一用到跨平台的引擎必然要有引擎与各平台原生进行交互通信的需要.那么Himi先讲解React Native与iOS之间的通信交互. 本篇主要分为两部分讲解:(关于其中讲解的OC语法等不介绍,不懂的请自行学习) 1. React Native 访问iOS 2. iOS访问React Native     一:React Native 访问iOS 1. 我们想要JS调用OC函数,就要实现一个"RCTBridgeModule"协议的Objective-C类 所以首先我们先创建一个oc新类,  

【REACT NATIVE 系列教程之十一】插件的安装、使用与更新(示例:REACT-NATIVE-TAB-NAVIGATOR)

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2294.html 本篇主要来详细介绍如何安装.升级插件及讲解一个react-native-tab-navigator的示例. 首先推荐一个插件网站:https://www.npmjs.com     (此插件属于半官方维护的) 本文举例使用的插件:react-native-tab-navigator ,选项卡形式的导

【REACT NATIVE 系列教程之七】统一ANDROID与IOS两个平台的程序入口&&区分平台的组件简介

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2260.html       本篇介绍两个细节:       1. 关于如何将index.android.js 与index.ios.js统一管理起来.       2.  Platform 组件的简单介绍与使用   一:将index.android.js 与index.ios.js统一管理起来. 由于React本身

【REACT NATIVE 系列教程之一】触摸事件的两种形式与四种TOUCHABLE组件详解

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2203.html 本文是RN(React Native)系列教程第一篇,当然也要给自己的群做个广告:   React Native @Himi :126100395  刚创建的群,欢迎一起学习.讨论.进步. 本文主要讲解两点: 1.   PanResponder:触摸事件,用以获取用户手指所在屏幕的坐标(x,y)或触

React Native 系列(九)

前言 本系列是基于React Native版本号0.44.3写的.很多的App都使用了Tab标签组件,例如QQ,微信等等,就是切换不同的选项,显示不同的内容.那么这篇文章将介绍RN中的Tab标签组件. Tab标签 什么是Tab标签?(ps:我是这样叫的),就拿微信来说吧,底部有4个选项卡,点击不同的按钮切换不同的内容.在RN中有两个组件负责实现这样的效果,它们是: TabBarIOS TabNavigator TabBarIOS 和NavigatorIOS相似,看名字就知道该组件只适用于iOS,

React Native 系列(六)

前言 本系列是基于React Native版本号0.44.3写的.在我们之前的通过props实现组件间传值的时候,大家有没有发现在父组件传递值过去,在子控件获取props的时候没有提示,那么如何能实现让其有提示呢?这篇文章将带领大家去认识一下PropTypes这个玩意. PropTypes 问题: 在自定义组件的时候,通常需要暴露属性出去,并且设置属性类型,外界在使用自定义组件的属性的时候,需要有自动提示属性功能. 解决: 使用PropTypes PropTypes用处: 可以实现类型检查,当传