此博客基于react-native-0.48.4
ListView简介
一个核心组件,用于高效地显示一个可以垂直滚动的变化的数据列表。最基本的使用方式就是创建一个ListView.DataSource数据源,然后给它传递一个普通的数据数组,再使用数据源来实例化一个ListView组件,并且定义它的renderRow回调函数,这个函数会接受数组中的每个数据作为参数,返回一个可渲染的组件(作为listview的每一行)
- ListView文档同时它还有个离不开的ListView.DataSource就好比在Android中的
Adapter
- 虽然现在这个组件已经过期,官方建议使用FlatList或SectionList代替
- 当是我们还是得来学习一下,毕竟以后搞项目遇到了不会一脸懵逼。
现在来实现一个最简单的列表
效果图:
- 首先创建一个
MyListView.js
组件并创建好数据源
constructor(props) {
super(props);
//1.初始化ListView.DataSource数据源
var data = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
//传入我们需要展示的数据
data: data.cloneWithRows(this.getArrays()),
}
}
- 创建我们的测试数据
//动态获取item内容
getArrays() {
var list = [];
for (var i = 0; i < 20; i++) {
list.push(
new this.ItemData('我是标题' + '---' + i, '我是内容' + '---' + i, i)
);
}
return list;
}
ItemData
这个拿Java来说就是一实体类Bean对象
//存储每个item对象的数据
ItemData(title, content, position) {
this.position = position;
this.title = title;
this.content = content;
}
经过上面三步,我们的
ListView.DataSource
数据源就创建好了,接下来就是对数据进行展示了。
数据的展示 Item布局渲染
render() {
return (
<ListView
//设置数据源
dataSource={this.state.data}
//相当于Android中Adapter的getView 渲染每一个Item
renderRow={this.getView}/>
)
}
- 重点就在这个renderRow函数了,渲染每一个Item进行数据展示
/**
* renderRow中可以使用的参数(rowData, sectionID, rowID, highlightRow)
* @param rowData
* @returns {XML}
*/
getView(rowData) {
//这里返回的就是每个Item
return (
<TouchableOpacity activeOpacity={0.5}
onPress={() => ToastAndroid.show(rowData.position + '', ToastAndroid.SHORT)}>
<View style={styles.item}>
<Text>{rowData.title}</Text>
<Text style={{marginTop: 5, fontSize: 12}}>{rowData.content}</Text>
</View>
</TouchableOpacity>
)
}
//样式
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
borderBottomWidth: 0.5,
borderBottomColor: '#dddddd',
height: 60,
}
- renderRow中可以使用的参数(rowData, sectionID, rowID, highlightRow),具体的使用可以参照官方文档
rowData
也就是我们一开始初始化好的数据ItemData
实例- 在Item的最外层套了一层
TouchableOpacity
用来实现Item的点击事件 - 使用ListView也就三步:定义ListView.DataSource构造数据源、编写ListViwe、实现renderRow编写Item样式。
当然通过ListView可以实现一个GridView效果,只需要修改一下ListView的主轴方向即可;创建数据源之类操作和上面一样
render() {
return (
<ListView
dataSource={this.state.data}
contentContainerStyle={styles.list}
//相当于Android中Adapter的getView 渲染每一个Item
renderRow={this.getView}
pageSize={20}/>
)
}
//样式
list: {
//横向
flexDirection: 'row',
flexWrap: 'wrap',
}
pageSize
当为横向的时候需要指定这个属性,值就为你要显示数据的大小(暂时不知道为什么要这样,先记录下)- 当列表为水平方向且包裹内容时,要达到GridView效果我们需要自己计算每个Item的宽度并且平分屏幕的宽度就可以了。
获取屏幕的宽度,并计算出每一个Item的宽度
//屏幕信息
var dimensions = require('Dimensions');
//获取屏幕的宽度
var {width} = dimensions.get('window');
var columns = 3;//每一行显示多少列
var itemWidth = width / columns;//每一个item所占的宽度
有了宽度我们就需要修改每个Item的宽度和其他样式了,如下:
item: {
justifyContent: 'center',
alignItems: 'center',
borderWidth: 0.5,
borderColor: '#dddddd',
width: itemWidth,
height: 60,
},
效果图:
GridView源码看这里
讲到这里ListView控件的基本使用相信大家已经掌握了,那我们就来写个真实的案例,从服务器请求json数据并通过ListView列表展示。
万物基于效果图:
这里就涉及我们的网络请求和json数据处理来,不过也是很简单的。先来说说第一部分请求网络数据:
static defaultProps = {
url: 'https://news-at.zhihu.com/api/4/news/latest'
};
- 同时初始化好我们的数据源,此时并没有数据所以知识先创建来一个对象;待会请求到了数据直接往里面放就可以了。
constructor(props) {
super(props);
//1.初始化ListView.DataSource数据源
this.state = {
data: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),
}
}
- 请求数据就只需要在组件渲染完成即可
//渲染完成,请求网络数据
componentDidMount() {
fetch(this.props.url)
//将响应到的数据转化为json
.then((response) => response.json())
.then((response) => {
//解析json数据
var json = response['stories'];
//更新状态机
this.setState({
data: this.state.data.cloneWithRows(json),
});
})
.catch((error) => {
if (error) {
//网络错误处理
console.log('error', error);
}
})
}
来看下返回的数据格式,这样结合代码会更加的直观
{
"date": "20170928",
"stories": [
{
"images": [
"https://pic2.zhimg.com/v2-6707daba106f3c4286ea497d6e9b9759.jpg"
],
"type": 0,
"id": 9636088,
"ga_prefix": "092821",
"title": "这可能是丁丁出现次数最多的美剧"
},
{
"images": [
"https://pic1.zhimg.com/v2-629d7c83a17d14f9117f9b3d019e3774.jpg"
],
"type": 0,
"id": 9635776,
"ga_prefix": "092819",
"title": "吸尘器制造商戴森要在 2020 年推出电动汽车,这是 70 岁发明家的野心"
},
//...
}
var json = response['stories'];
这样就拿到了stories
里面的所有数据并且是个数组,数组的每个元素里面有有images
数组、type
、id
、ga_prefix
、title
也就是下面我们用到的RowData
有了数据源就需要在渲染Item的时候设置在文本上了,展示出来:
getView(rowData) {
//这里返回的就是每个Item
return (
<TouchableOpacity activeOpacity={0.5}
onPress={() => ToastAndroid.show(rowData.title, ToastAndroid.SHORT)}>
<View style={styles.item}>
{/*左边的图片*/}
<Image source={{uri: rowData.images[0]}} style={styles.image}/>
<View style={styles.left}>
{/*右边的View*/}
<Text style={{marginTop: 15, color: '#333333'}}>{rowData.title}</Text>
<View style={styles.content}>
<Text style={{flex: 1, textAlign: 'right'}}>{rowData.id + ''}</Text>
</View>
</View>
</View>
</TouchableOpacity>
)
}
个人觉得js上解析json真的是神奇,一个var 遍历定义所有类型很是舒服;哈哈哈…