React-Native在0.43推出了兩款新的列表組件:FlatList(高性能的簡單列表組件)和SectionList(高性能的分組列表組件).html
從官方上它們都支持經常使用的如下功能:node
其中,SectionList適合分組/類/區,可是在0.43版本中,若是但願section的頭部可以吸頂懸浮,請暫時先使用老版的<ListView>.
react
它們都是基於<VirtualizedList>
組件的封裝(不一樣於ListView,ListView是繼承自ScrollView,這意味着ListView可使用全部ScrollView的屬性,可是不帶重用,性能稍微不足,也就是說FlatList.SectionList這兩款組件和ListView,ScrollView沒啥關係,而ListView和ScrollView是父子關係),.因此須要注意幾點.詳細的請在官方瀏覽.其中有一點必須注意:在使用時,默認狀況下每行都須要提供一個不重複的key屬性.也能夠提供一個keyExtractor
函數來動態綁定數據源中的id等其餘不惟一的數據。若是不綁定會報一個警告:git
接下里使用這兩個組件寫一個demo:列表組件的聯動(ps:其實我的感受使用ListView實現更加方便.也更易擴展)github
數據源咱們採用本地數據:json
{ "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)react-native
/** * 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.ide
/** * 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