React-Native新列表組件FlatList和SectionList學習 | | 聯動列表實現

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"
        }
      ]
    }
  ]
}
View Code

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,
    },
});
View Code

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,
    }
});
View Code

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); //發監聽
        }
    }


}
View Code

其中,使用事件監聽來實現點擊和滑動的監聽.佈局

咱們使用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);
    }
}
View Code

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

相關文章
相關標籤/搜索