React-Native新列表组件FlatList和SectionList学习 | | 联动列表实现
React-Native在0.43推出了两款新的列表组件:FlatList(高性能的简单列表组件)和SectionList(高性能的分组列表组件).
从官方上它们都支持常用的以下功能:
- 完全跨平台。
- 支持水平布局模式。
- 行组件显示或隐藏时可配置回调事件。
- 支持单独的头部组件。
- 支持单独的尾部组件。
- 支持自定义行间分隔线。
- 支持下拉刷新。
- 支持上拉加载。
其中,SectionList适合分组/类/区,但是在0.43版本中,如果希望section的头部能够吸顶悬浮,请暂时先使用老版的<ListView>.
它们都是基于<VirtualizedList>
组件的封装(不同于ListView,ListView是继承自ScrollView,这意味着ListView可以使用所有ScrollView的属性,但是不带重用,性能稍微不足,也就是说FlatList.SectionList这两款组件和ListView,ScrollView没啥关系,而ListView和ScrollView是父子关系),.所以需要注意几点.详细的请在官方浏览.其中有一点必须注意:在使用时,默认情况下每行都需要提供一个不重复的key属性.也可以提供一个keyExtractor
函数来动态绑定数据源中的id等其他不唯一的数据。如果不绑定会报一个警告:
接下里使用这两个组件写一个demo:列表组件的联动(ps:其实个人感觉使用ListView实现更加方便.也更易扩展)
数据源我们采用本地数据:
{
"food_spu_tags":[ {
"title":"1",
"data":[
{
"name":"一 nghnh",
"key":"1"
},
{
"name":"一 tyui22uyt",
"key":"2"
},
{
"name":"一 3fdsfdga",
"key":"3"
}
]
},
{
"title":"2",
"data":[
{
"name":"二 fsd",
"key":"4"
},
{
"name":"二 gfdh",
"key":"5"
},
{
"name":"二 ghdsfd",
"key":"6"
},
{
"name":"二 hkjhg",
"key":"7"
},
{
"name":"二 oiuytre",
"key":"8"
},
{
"name":"二 phfd",
"key":"9"
}
]
},
{
"title":"3",
"data":[
{
"name":"三 pknbv",
"key":"10"
},
{
"name":"三 qazxsef",
"key":"11"
},
{
"name":"三 plmnbgf",
"key":"12"
},
{
"name":"三 ggggg",
"key":"13"
},
{
"name":"三 gfd",
"key":"14"
},
{
"name":"三 fgh",
"key":"15"
},
{
"name":"三 hhf",
"key":"16"
},
{
"name":"三 jff",
"key":"17"
},
{
"name":"三 sfgd",
"key":"18"
},
{
"name":"三 dffhsd",
"key":"19"
},
{
"name":"三 ghd",
"key":"20"
},
{
"name":"三 ghsg",
"key":"21"
}
]
},
{
"title":"4",
"data":[
{
"name":"四 ghs",
"key":"22"
},
{
"name":"四 hth",
"key":"23"
}
]
},
{
"title":"5",
"data":[
{
"name":"五 teh",
"key":"24"
},
{
"name":"五 thtr",
"key":"25"
},
{
"name":"五 thereth",
"key":"26"
},
{
"name":"五 yefdgs",
"key":"27"
},
{
"name":"五 htweh",
"key":"28"
},
{
"name":"五 thrhwt",
"key":"29"
},
{
"name":"五 geheht",
"key":"30"
},
{
"name":"五 thwtw",
"key":"31"
}
]
},
{
"title":"6",
"data":[
{
"name":"六 thsfsg",
"key":"32"
},
{
"name":"六 thwfs",
"key":"33"
},
{
"name":"六 htsfd",
"key":"34"
}
]
},
{
"title":"7",
"data":[
{
"name":"七 hgshfd",
"key":"35"
}
]
},
{
"title":"8",
"data":[
{
"name":"八 rgdsgsfd",
"key":"36"
},
{
"name":"八 grht",
"key":"37"
},
{
"name":"八 htrfss",
"key":"38"
},
{
"name":"八 thsgfd",
"key":"39"
},
{
"name":"八 hthe",
"key":"40"
},
{
"name":"八 trgtsf",
"key":"41"
},
{
"name":"八 f45f",
"key":"42"
},
{
"name":"八 4qtq",
"key":"43"
},
{
"name":"八 43f",
"key":"44"
},
{
"name":"八 43ff",
"key":"45"
},
{
"name":"八 45gwrsfd",
"key":"46"
}
]
},
{
"title":"9",
"data":[
{
"name":"九 43qgf",
"key":"47"
},
{
"name":"九 ref3",
"key":"48"
},
{
"name":"九 54sf",
"key":"49"
}
]
},
{
"title":"10",
"data":[
{
"name":"十 43refsd",
"key":"50"
},
{
"name":"十 43refzd",
"key":"51"
},
{
"name":"十 4q3gfd",
"key":"52"
},
{
"name":"十 wgf",
"key":"53"
},
{
"name":"十 4q3fs",
"key":"54"
}
]
},
{
"title":"11",
"data":[
{
"name":"十一 wrf",
"key":"55"
},
{
"name":"十一 5ersf",
"key":"56"
},
{
"name":"十一 43fs",
"key":"57"
},
{
"name":"十一 43fs",
"key":"58"
},
{
"name":"十一 5gs",
"key":"59"
},
{
"name":"十一 w5gfsd",
"key":"60"
},
{
"name":"十一 4qrgfs",
"key":"61"
}
]
},
{
"title":"12",
"data":[
{
"name":"十二 4wgfsd",
"key":"62"
},
{
"name":"十二 w5gfsd",
"key":"63"
},
{
"name":"十二 4qgfsgf",
"key":"64"
},
{
"name":"十二 3qgsf",
"key":"65"
}
]
}
]
}
1.新建个主类放置左右两个列表组件(左边的FlatList右边的SectionList)
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/ import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import LeftFlatList from './leftFlatList'
import RightSectionList from './RightSectionList'
import linkageData from './linkage.json'
export default class Main extends Component {
render() {
return (
<View style={{flexDirection:'row'}}>
<LeftFlatList data = {linkageData}/>
<RightSectionList data = {linkageData}/>
</View>
);
}
} const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
2.左边的FlatList,key采用keyExtractor函数绑定,就是数据源中title.
/**
* Created by shaotingzhou on 2017/6/22.
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
Platform,
Dimensions,
RefreshControl,
FlatList,
ActivityIndicator,
DeviceEventEmitter,
ScrollView
} from 'react-native';
var {width,height} = Dimensions.get('window');
var dataAry = [] export default class LeftFlatList extends Component{
// 构造
constructor(props) {
super(props);
dataAry = this.props.data.food_spu_tags
this.state = {
dataAry: dataAry,
cell:0 //默认选中第一行
};
}
render() {
return (
<FlatList
ref='FlatList'
style={{width:80}}
data = {this.state.dataAry} //数据源
renderItem = {(item) => this.renderRow(item)} //每一行render
ItemSeparatorComponent = {()=>{return(<View style={{height:1,backgroundColor:'cyan'}}/>)}} //分隔线
keyExtractor={this.keyExtractor} //使用json中的title动态绑定key
/>
);
}
//使用json中的title动态绑定key
keyExtractor(item: Object, index: number) {
return item.title
}
//每一行render
renderRow =(item) =>{
return(
<TouchableOpacity onPress={()=>this.cellAction(item)}>
<View style={{height:60,flexDirection:'row',alignItems:'center'}}>
<View style={{height:50,width:5,backgroundColor: item.index == this.state.cell ? 'red' : 'rgba(0,0,0,0)'}}/>
<Text style={{marginLeft:20}}>{item.item.title}</Text>
</View>
</TouchableOpacity>
)
}
//点击某行
cellAction =(item)=>{
// alert(item.index)
if(item.index < this.state.dataAry.length - 1){
this.setState({
cell:item.index
})
DeviceEventEmitter.emit('left',item.index); //发监听
} } componentWillUnmount(){
// 移除监听
this.listener.remove();
} componentWillMount() {
this.listener = DeviceEventEmitter.addListener('right',(e)=>{
this.refs.FlatList.scrollToIndex({animated: true, index: e-1})
this.setState({
cell:e-1
})
});
} }; var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
}
});
3.右边的SectionList,key采用数据源中id来绑定.
/**
* Created by shaotingzhou on 2017/6/22.
*/
import React, {Component} from 'react';
import {
StyleSheet,
View,
Text,
SectionList,
Dimensions,
DeviceEventEmitter,
ScrollView
} from 'react-native';
var {width,height} = Dimensions.get('window');
var sectionData = []
export default class RightSectionList extends Component {
// 构造
constructor(props) {
super(props);
sectionData = this.props.data.food_spu_tags
this.state = {
sectionData:sectionData
};
}
//行
renderItem = (item) => {
return (
<View style={{height:60,justifyContent:'center',marginLeft:15}}>
<Text>{item.item.name}</Text>
</View>
)
}
//头
sectionComp = (section) => {
return (
<View style={{height:30,backgroundColor:'#DEDEDE',justifyContent:'center',alignItems:'center'}}>
<Text >{section.section.title}</Text>
</View>
)
} render() {
return (
<SectionList
ref='sectionList'
style={{width:width-80}}
renderSectionHeader={(section)=>this.sectionComp(section)} //头
renderItem={(item)=>this.renderItem(item)} //行
ItemSeparatorComponent = {()=>{return(<View style={{height:1,backgroundColor:'black'}}/>)}}//分隔线
sections={this.state.sectionData} //数据
onViewableItemsChanged = {(info)=>this.itemChange(info)} //滑动时调用
/> );
} componentDidMount() {
//收到监听
this.listener = DeviceEventEmitter.addListener('left',(e)=>{
// console.log(e + 1) // 左边点击了第几行
// console.log(sectionData) // 数据源
// console.log(sectionData[e])
// console.log(sectionData[e].data.length)
// SectionList实现scrollToIndex需要修改VirtualizedSectionList和SectionList源码
if(e > 0){
//计算出前面有几行
var count = 0
for(var i = 0; i < e; i++){
count += sectionData[i].data.length +1
}
this.refs.sectionList.scrollToIndex({animated: true, index: count})
}else {
this.refs.sectionList.scrollToIndex({animated: true, index: 0}) //如果左边点击第一行,右边则回到第一行
} });
} componentWillUnmount(){
// 移除监听
this.listener.remove();
} itemChange = (info)=>{
let title = info.viewableItems[0].item.title
var reg = new RegExp("^[0-9]*$");
if (reg.test(title)) {
DeviceEventEmitter.emit('right',title); //发监听
}
} }
其中,使用事件监听来实现点击和滑动的监听.
我们使用scrollToIndex来移动.但是呢,FlatList对VirtualizedList封装的时候有添加这个方法,而SectionList并没有(why?).无奈自己修改下它的源码.
a.在node_modules/react-native/Libraries/Lists/SectionList.js 下修改 250-310行代码为
class SectionList<SectionT: SectionBase<any>>
extends React.PureComponent<DefaultProps, Props<SectionT>, void> {
props: Props<SectionT>;
static defaultProps: DefaultProps = defaultProps; render() {
const List = this.props.legacyImplementation ? MetroListView : VirtualizedSectionList;
return <List
ref={this._captureRef}
{...this.props} />;
} _captureRef = (ref) => {
this._listRef = ref;
}; scrollToIndex = (params: { animated?: ?boolean, index: number, viewPosition?: number }) => {
this._listRef.scrollToIndex(params);
}
}
b.在node_modules/react-native/Libraries/Lists/VirtualizedSectionList.js 下的335下面增加
scrollToIndex = (params: { animated?: ?boolean, index: number, viewPosition?: number }) => {
this._listRef.scrollToIndex(params);
}
修改后完整源码见:SectionList.js VirtualizedSectionList.js.
OK.修改完成后就可以实现点击左联右了.
而右联左,通过SectionList的onViewableItemsChanged属性实现.
以后就是关于FlatList和SectionList的学习demo.
再说一遍,实现联动组件最好使用ListView.因为现阶段官方推出的FlatList和SectionList的方法较少,bug较多.
demo源码github:https://github.com/pheromone/RN-FlatList-SectionList
React-Native新列表组件FlatList和SectionList学习 | | 联动列表实现的更多相关文章
- React Native之获取通讯录信息并实现类通讯录列表(ios android)
React Native之获取通讯录信息并实现类通讯录列表(ios android) 一,需求分析 1,获取通讯录信息,筛选出通讯录里有多少好友在使用某个应用. 2,获取通讯录信息,实现类通讯录,可拨 ...
- react native之组织组件
这些组件包括<TabView>,<NavigatorView>和<ListView>,他们实现了手机端最常用的交互和导航.你会发现这些组件在实际的项目中会非常有用. ...
- React Native之倒计时组件的实现(ios android)
React Native之倒计时组件的实现(ios android) 一,需求分析 1,app需实现类似于淘宝的活动倒计时,并在倒计时结束时,活动也结束. 2,实现订单倒计时,并在倒计时结束时,订单关 ...
- React Native知识6-NavigatorIOS组件
NavigatorIOS包装了UIKit的导航功能,可以使用左划功能来返回到上一界面.本组件并非由Facebook官方开发组维护.这一组件的开发完全由社区主导.如果纯js的方案能够满足你的需求的话,那 ...
- React Native常用第三方组件汇总--史上最全 之一
React Native 项目常用第三方组件汇总: react-native-animatable 动画 react-native-carousel 轮播 react-native-countdown ...
- React Native常用第三方组件汇总--史上最全[转]
本文出处: http://blog.csdn.net/chichengjunma/article/details/52920137 React Native 项目常用第三方组件汇总: react-na ...
- 从零学React Native之12 组件的生命周期
一个React Native组件从它被加载,到最终被卸载会经历一个完整的生命周期.所谓生命周期,就是一个对象从开始生成到最后消亡所经历的状态,理解生命周期,是合理开发的关键. ES6语法和之前的ES5 ...
- React Native知识2-Text组件
Text用于显示文本的React组件,并且它也支持嵌套.样式,以及触摸处理.在下面的例子里,嵌套的标题和正文文字会继承来自styles.baseText的fontFamily字体样式,不过标题上还附加 ...
- react native 之子组件和父组件之间的通信
react native开发中,为了封装性经常需要自定义组件,这样就会出现父组件和子组件,那么怎么在父组件和子组件之间相互通信呢,也就是怎么在各自界面push和pop.传值. 父组件传递给子组件: 父 ...
随机推荐
- MySQL中group by , sum , case when then 的使用
在我们使用数据库的时候,可能会遇到需要进行统计的情况. 比如需要统计一下,下表中各个年份的胜负场数. 遇到这样的情况,我们应该怎么办呢? 在mysql中我们可以使用group by sum case ...
- 算法(第四版)C# 习题题解——1.2
写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 这一节内容可能会用到的库文件有 ...
- 【BZOJ1485】有趣的数列
Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…&l ...
- sqldeveloper 重置java.exe路径方法
sqldeveloper重新配置java.exe 1.进入D:\app\product\11.2.0\dbhome_1\sqldeveloper\sqldeveloper\bin路径下,找到sqlde ...
- 表单提交:button input submit 的区别
http://harttle.com/2015/08/03/form-submit.html 最近项目代码中的表单提交的方式已经百花齐放了,现在用这篇文章来整理一下不同表单提交方式的区别,给出最佳实践 ...
- png转tif
发国外的文章要求图片是tif,cmyk色彩空间的. 大小尺寸还有要求. 比如 网上大神多,找到了一段代码,感谢! https://www.jianshu.com/p/ec2af4311f56 http ...
- fiddler修改response header
if(oSession.host.Contains("baidu.com")){//根据host判断 oSession.RequestHeaders.Remove("Ac ...
- Matlab:高阶常微分三种边界条件的特殊解法(隐式Euler)
函数文件1: function b=F(f,x0,u,h) b(1,1)=x0(1)-h*x0(2)-u(1); b(2,1)=x0(2)+h*x0(1)^2-u(2)-h*f; 函数文件2: fun ...
- Python人工智能之路 - 第二篇 : 算法实在太难了有现成的直接用吧
本节内容 预备资料: 1.FFmpeg: 链接:https://pan.baidu.com/s/1jonSAa_TG2XuaJEy3iTmHg 密码:w6hk 2.baidu-aip: pip ins ...
- 破解 JS(原型)继承
总体分为四大类:利用空对象作为中介继承.Object.create 继承.setPrototypeOf 继承.拷贝继承 function Animal(name, age) { this.name = ...