React Native——組件FlatList
屬性
添加頭部組件
ListHeaderComponent
屬性用來給FlatList添加頭部組件
簡單使用:
//ES6之前寫法 _header = function () { return ( <Text style={{fontWeight: ‘bold‘, fontSize: 20}}>熱門電影</Text> ); } <FlatList ListHeaderComponent={this._header}//header頭部組件 />
添加尾部組件
ListFooterComponent
屬性為FlatList添加尾部組件,接收的參數跟ListHeaderComponent
//ES6的寫法 _footer = () => ( <Text style={{fontSize: 14, alignSelf: ‘center‘}}>到底啦,沒有啦!</Text> ) <FlatList ListFooterComponent={this._footer} //添加尾部組件 />
添加頭部和尾部組件比較簡單,需要註意的就是上邊兩者ES5和6寫法的區別!
添加分割線
ItemSeparatorComponent
屬性可以為FlatList列表之間添加分割線。
舉個例子:
class ItemDivideComponent extends Component { render() {return ( <View style={{height: 1, backgroundColor: ‘skyblue‘}}/> ); } }; <FlatList ItemSeparatorComponent={ItemDivideComponent}//分割線組件 />
這裏我們自定義了一個組件來設置分割線,當然我們像添加頭部和尾部一樣,在內部聲明之後使用this._header
的寫法也是可以的!
設置空數據視圖
ListEmptyComponent
屬性,可以為FlatList設置一個沒有數據的時候展示的視圖!,這個屬性可以接收的參數類型比較多,可以是React Component
render函數
,或者渲染好的element
。 所以設置空數據視圖不僅可以像前邊介紹的兩種方式以外,還可以接收一個
render函數
。 舉個例子:
createEmptyView() { return ( <Text style={{fontSize: 40, alignSelf: ‘center‘}}>還沒有數據哦!</Text> ); } <FlatList ListEmptyComponent={this.createEmptyView()} />
設置item的key
在前一篇博客中,我們的設置data
的時候,是這樣的:
data={[ {key: ‘大護法‘}, {key: ‘繡春刀II:修羅戰場‘}, ... ]}
類似{key:你的數據value}
這樣的形式,是因為我們在設置data
的時候,必須要為item設置key
屬性,否則會有一個黃色的警告彈出。而且我們需要註意的是這裏每一個item的key
是唯一的!,如果按照這樣的寫法,我們在數據中有重復的,比如{key: ‘大護法‘},{key: ‘大護法‘}
,這裏的大護法
只會顯示一個,因為FlatList會認為這是一條數據,因為key
相同!
那麽為什麽會這樣?
因為FlatList中有一個屬性:keyExtractor
,用於為給定的item生成一個不重復的key。若不指定此函數,則默認抽取item.key作為key值。若item.key也不存在,則使用數組下標index。因為前邊沒有指定該屬性,所以就把item.key
作為了key值,才會認定兩個重復的數據是一條數據!
那麽一般地,我們可以這樣使用:
_keyExtractor = (item, index) => index; <FlatList keyExtractor={this._keyExtractor} />
這樣就把data
中數組的下標作為了唯一的key
。
那麽在data
中指定數據的時候,就不用{key: ‘大護法‘}
這樣寫了,因為我們已經指定了唯一的key,而可以隨意寫{name: ‘大護法‘}
或者{movie: ‘大護法‘}
,在渲染item的時候,取值用item.name
或者item.movie
即可!也不會有黃色的警告出現!
你明白了嗎?
設置itemLayout
getItemLayout
屬性是一個可選的優化,用於避免動態測量內容尺寸的開銷。如果我們知道item的高度,就可以為FlatList指定這一個屬性,來使FlatList更加高效的運行!
舉個例子:
getItemLayout={(data, index) => ({ length: 44, offset: (44 + 1) * index, index })}
我們在上邊使用的時候指定了item的高度為44,所以length
參數為44;我們設置了分割線,且指定分割線的高度是1,所以offset
參數為44+1。綜合來看,設置這個屬性應這樣寫:
getItemLayout={(data, index) => ({ length: 你的item的height, offset: (你的item的height + ItemSeparator的height) * index, index })}
設置這一屬性,在調用FlatList的跳轉函數的時候非常有用,否則可能會很卡頓!如scrollToEnd()
,scrollToIndex()
,這兩個方法後邊再說!
下拉刷新
FlatList中有兩個屬性,可以用來設置下拉刷新。
refreshing
在等待加載新數據時將此屬性設為true,列表就會顯示出一個正在加載的符號.onRefresh
如果設置了此選項,則會在列表頭部添加一個標準的RefreshControl
控件,以便實現“下拉刷新”的功能。同時你需要正確設置refreshing
屬性。
這裏的RefreshControl
控件,非常類似於Android v4包中的SwipeRefreshLayout
,這裏就不多說了,需要了解的可以查看相關文檔!
如何使用,舉個例子:
refreshing={this.state.refreshing} onRefresh={() => { this.setState({refreshing: true})//開始刷新 //這裏模擬請求網絡,拿到數據,3s後停止刷新 setTimeout(() => { alert(‘沒有可刷新的內容!‘); this.setState({refreshing: false});//停止刷新 }, 3000); }}
上拉加載
關於上拉加載,FlatList也封裝有兩個屬性來實現:
onEndReachedThreshold
:這個屬性決定當距離內容最底部還有多遠時觸發onEndReached回調。需要註意的是此參數是一個比值而非像素單位。比如,0.5表示距離內容最底部的距離為當前列表可見長度的一半時觸發。所以它的取值範圍為:(0,1),不包含0和1。onEndReached
:列表被滾動到距離內容最底部不足onEndReachedThreshold設置的的距離時調用。
具體使用,舉個例子:
onEndReachedThreshold={0.1} onEndReached={({distanceFromEnd}) => ( setTimeout(() => { this.setState((state) => ({ data: state.data.concat(this._newData), })); }, 3000) )}
這裏我們設置的距離為列表可見長度的1/10,而觸發了onEndReached函數時,我們設置了一個定時器,3s後,將data
中的數據添加了新數據,從而達到上拉加載更多的效果!
函數
介紹
FlatList下有兩個比較常用的函數:
scrollToEnd() 滾動到底部。如果不設置getItemLayout屬性的話,可能會比較卡。
scrollToIndex()如果不設置getItemLayout屬性的話,無法跳轉到當前可視區域以外的位置。
如官方所言,使用這兩個函數的時候,最好指定設置getItemLayout
屬性。
使用
因為這兩個是FlatList組件的函數,所以在使用這兩個函數之前,首先我們要得到FlatList組件的引用。
這時候就需要ref
屬性。react提供的這個ref
屬性,表示為對組件真正實例的引用。
關於ref
屬性的使用,可以去React官網查看API!
具體的使用:
ref={(flatList) => this._flatList = flatList} this._flatList.scrollToEnd(); //viewPosition參數:0表示頂部,0.5表示中部,1表示底部 this._flatList.scrollToIndex({viewPosition: 0, index: this.state.text});
至此,關於FlatList進階的相關基礎內容就說完了!
完整的Demo
class FlatListTest extends Component { constructor(props) { super(props); this.state = { data: this._sourceData, refreshing: false, //初始化不刷新 text: ‘‘//跳轉的行 }; } _header = function () { return ( <Text style={{fontWeight: ‘bold‘, fontSize: 20}}>熱門電影</Text> ); } _footer = () => ( <Text style={{fontSize: 14, alignSelf: ‘center‘}}>到底啦,沒有啦!</Text> ) createEmptyView() { return ( <Text style={{fontSize: 40, alignSelf: ‘center‘}}>還沒有數據哦!</Text> ); } //此函數用於為給定的item生成一個不重復的key //若不指定此函數,則默認抽取item.key作為key值。若item.key也不存在,則使用數組下標index。 _keyExtractor = (item, index) => index; itemClick(item, index) { alert(‘點擊了第‘ + index + ‘項,電影名稱為:‘ + item.name); } _renderItem = ({item, index}) => { return ( <TouchableOpacity activeOpacity={0.5} onPress={this.itemClick.bind(this, item, index)}> <Text style={flatListStyles.item}>{item.name}</Text> </TouchableOpacity> ); } //點擊按鈕跳轉 onButtonPress() { //viewPosition參數:0表示頂部,0.5表示中部,1表示底部 this._flatList.scrollToIndex({viewPosition: 0, index: this.state.text}); //this._flatList.scrollToOffset({ animated: true, offset: 2000 }); }; onBtnPress2Botton() { this._flatList.scrollToEnd(); } _sourceData = [ {name: ‘大護法‘}, {name: ‘繡春刀II:修羅戰場‘}, {name: ‘神偷奶爸3‘}, {name: ‘神奇女俠‘}, {name: ‘摔跤吧,爸爸‘}, {name: ‘悟空傳‘}, {name: ‘閃光少女‘}, {name: ‘攻殼機動隊‘}, {name: ‘速度與激情8‘}, {name: ‘蝙蝠俠大戰超人‘}, {name: ‘攻殼機動隊‘}, {name: ‘速度與激情8‘}, {name: ‘蝙蝠俠大戰超人‘} ] _newData = [{name: ‘我是新添加的數據1‘}, {name: ‘我是新添加的數據2‘}, {name: ‘我是新添加的數據3‘}] render() { return ( <View style={flatListStyles.container}> <View style={{flexDirection: ‘row‘, justifyContent: ‘center‘, alignItems: ‘center‘}}> <TextInput style={{flex: 1}} placeholder="請輸入要跳轉的行號" onChangeText={(text) => this.setState({text})} /> <Button title="跳轉到行" onPress={this.onButtonPress.bind(this)} color={‘skyblue‘}/> <Button title="跳轉到底部" onPress={this.onBtnPress2Botton.bind(this)} color={‘green‘}/> </View> <FlatList data={this.state.data} //使用 ref 可以獲取到相應的組件 ref={(flatList) => this._flatList = flatList} ListHeaderComponent={this._header}//header頭部組件 ListFooterComponent={this._footer}//footer尾部組件 ItemSeparatorComponent={ItemDivideComponent}//分割線組件 //空數據視圖,可以是React Component,也可以是一個render函數,或者渲染好的element。 ListEmptyComponent={this.createEmptyView()} keyExtractor={this._keyExtractor} //是一個可選的優化,用於避免動態測量內容尺寸的開銷,不過前提是你可以提前知道內容的高度。 //如果你的行高是固定的,getItemLayout用起來就既高效又簡單. //註意如果你指定了SeparatorComponent,請把分隔線的尺寸也考慮到offset的計算之中 getItemLayout={(data, index) => ( {length: 44, offset: (44 + 1) * index, index} )} //決定當距離內容最底部還有多遠時觸發onEndReached回調。 //註意此參數是一個比值而非像素單位。比如,0.5表示距離內容最底部的距離為當前列表可見長度的一半時觸發。 onEndReachedThreshold={0.1} //當列表被滾動到距離內容最底部不足onEndReachedThreshold的距離時調用 onEndReached={({distanceFromEnd}) => ( setTimeout(() => { this.setState((state) => ({ data: state.data.concat(this._newData), })); }, 3000) )} refreshing={this.state.refreshing} onRefresh={() => { this.setState({refreshing: true})//開始刷新 //這裏模擬請求網絡,拿到數據,3s後停止刷新 setTimeout(() => { alert(‘沒有可刷新的內容!‘); this.setState({refreshing: false}); }, 3000); }} renderItem={this._renderItem} /> </View> ); } } ; class ItemDivideComponent extends Component { render() { return ( <View style={{height: 1, backgroundColor: ‘skyblue‘}}/> ); } } ; const flatListStyles = StyleSheet.create({ container: { flex: 1, paddingTop: 22 }, item: { padding: 10, fontSize: 18, height: 44, }, }) AppRegistry.registerComponent(‘AwesomeProject‘, () => FlatListTest);
React Native——組件FlatList