1. 程式人生 > >React-Native新列表元件FlatList和SectionList學習 | | 聯動列表實現

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

React-Native在0.43推出了兩款新的列表元件:FlatList(高效能的簡單列表元件)和SectionList(高效能的分組列表元件).

http://www.cnblogs.com/shaoting/p/7069312.html

從官方上它們都支援常用的以下功能:

  • 完全跨平臺。
  • 支援水平佈局模式。
  • 行元件顯示或隱藏時可配置回撥事件。
  • 支援單獨的頭部元件。
  • 支援單獨的尾部元件。
  • 支援自定義行間分隔線。
  • 支援下拉重新整理。
  • 支援上拉載入。

其中,SectionList適合分組/類/區,但是在0.43版本中,如果希望section的頭部能夠吸頂懸浮,請暫時先使用老版的

它們都是基於<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);
    }

OK.修改完成後就可以實現點選左聯右了.

而右聯左,通過SectionList的onViewableItemsChanged屬性實現.

以後就是關於FlatList和SectionList的學習demo.

再說一遍,實現聯動元件最好使用ListView.因為現階段官方推出的FlatList和SectionList的方法較少,bug較多.


相關推薦

React-Native列表元件FlatListSectionList學習 | | 聯動列表實現

React-Native在0.43推出了兩款新的列表元件:FlatList(高效能的簡單列表元件)和SectionList(高效能的分組列表元件). http://www.cnblogs.com/shaoting/p/7069312.html 從官方上它們都支援常用

React Native 結合ScrollableTab、RefreshControlFlatList實現新聞分類列表

正好剛開始學RN,熟悉一下控制元件和基本使用。 涉及的知識點: 1、fetch網路請求,get 拼接引數,解析json。 2、ScrollableTabView、ScrollableTabBar 分類佈局。 3、FlatList 資料列表。 4、Navigation

關於React-native裡Android原生模組元件的寫法

原生模組就是把Android裡的API匯出來給JS呼叫,說簡單一點,就是讓自己寫的Java函式能夠在React Native的js程式碼裡呼叫。比如一些實現高效能的、多執行緒的程式碼,還有譬如圖片處理、資料庫、或者各種高階擴充套件等等。 舉個栗子: Toas

React Native的TextInput元件去掉下劃線使用背景圖片

      最近做RN,由於先做的是比較簡單的部分,所以沒碰到什麼難點。真正的難點還在後面,所以這周就記錄一下幾個小問題。也是比較常用的小問題了。 一、TextInput元件去掉下劃線和加上邊框       不得不說,RN自帶的TextInput輸入框是真的

React-Native系列》元件封裝之Dialog(iOSAndroid通用)

最近在專案中封裝了個Dialog元件,iOS和Android平臺上通用。 元件Dialog顯示時,從頁面頂部滑動到中間,點選確認或取消後,從頁面底部劃出頁面,需要注意動畫的實現。 原始碼如下: [javascript] view plain copy

React Native元件之SwipeableFlatList

做過移動開發的同學都應該清楚,側滑刪除是移動開發中的一個常見功能。在官方沒提供側滑元件之前,要實現側滑效果需要使用第三方庫,如react-native-swipe-list-view。不過隨著React Native 0.50版本的釋出,系統新新增Swipeab

React-Native開發五 React Native 的Image元件

1 Image元件介紹 RN中Image元件主要用於載入圖片,可載入靜態圖片,網路圖片,以及原生圖片,本地檔案系統中圖片資源 官方參考https://facebook.github.io/react-native/docs/image#resizemode 2 Image元件功

React-Native開發四 React Native 的Touchable元件

1 Touchable元件簡介 Touchable元件是RN的按鈕元件,一共有四大類 TouchableWithoutFeedback:不帶任何反饋的可觸控元件 TouchableHighlight:在TouchableWithoutFeedback的基礎上添加了當按下時背景會變

React Native圖片快取元件

今天介紹一個React Native的圖片快取元件 react-native-rn-cacheimage ,純JS實現,所以相容性很好。 大家都知道,其實React Native 的 Image 元件在 iOS 端實現了快取,而android 端仍未實現,而且,就算實現了 iOS端 ,可能有些需求仍然比較難

React Native 筆記之元件

React Native的元件 什麼是React Native 元件? React Native 都有哪些元件? 建立元件的三種方式 [元件的生命週期](https://react.docschina.org/docs/react-compone

react native獲取螢幕的寬度高度

var Dimensions = require('Dimensions'); var {width,height} = Dimensions.get("window");//第一種寫法 var width1 = Dimensions.get('window').width//第二種寫法 expor

React-Native 版本無法Debug問題

最近無聊+手殘 升級rn到最新版本,然後出現了無法debug問題 具體症狀表現為 (index):94 Uncaught TypeError: Cannot set property 'volume' of null at Object.render ((index):94

react native的Navigator元件示例

import React, {Component} from 'react';import {ScrollView, StyleSheet, Text, View, PixelRatio} from 'react-native';import { Navigator } from 'react-native-

react-native react-navigation的用法 react native 導航路由元件react-navigation的使用

  一、問題背景 react-navigation是react-native官方推薦的,基於Javascript的可擴充套件且使用簡單的導航,功能強大且完備   回顧一下,react-navigation包含以下功能來幫助我們建立導航器: StackN

react-native-vector-icons的安裝使用

react-native-vector-icons是一個React Native 專案使用最廣泛的向量圖示圖示庫,使用簡單,內容豐富。 react-native-vector-icons官網 react-native-vector-icons圖示展示列表 使用react-native-vector-icon

React Native關於ScrollableTabView元件

最近工作中使用ScrollableTabView元件的問題,實現如下圖所示的效果: render方法中判斷state中狀態,進行佈局控制 render(){ if(this.state.error){ return(

React Native封裝原生元件釋出到npm

因為一個任務,要寫原生的獲取使用者手機資料夾,實現使用者自定義資料夾的功能,寫好了之後嘗試封裝成元件。1. 首先,有一個rn專案,用Adnroid Studio開啟 android -> app -> build.gradle如圖新建一個 Android Modu

react native開發中eslint配置初始化

先簡單介紹一下mac系統環境下,eslint的配置。 首先開啟命令列工具,cd到專案根目錄下。 一次輸入命令並等待下載完成。 npm install eslint --save-dev npm ins

react native 倒計時控制元件

1.npm install //in package.json "dependencies": { "react_native_countdowntimer":"1.0.2" } //in your js code import CountDownTimer fr

React Native入門篇—react-native-splash-screen的安裝配置

注意:未經允許不可私自轉載,違者必究 React Native官方文件:https://reactnative.cn/docs/getting-started/ react-native-splash-screen官方文件:https://github.com/crazycod