react native基于FlatList下拉刷新上拉加载实现代码示例
网络 2018-10-30 1278
react native 的上拉加载一直困扰着自己,一直用的第三方组件,但是可维护性不高,而且也不太好用,最近工作没那么忙,就研究下了官方的FlatList,做出来的成果,比第三方组件流畅度高好多,而且也很好用
官方介绍:https://reactnative.cn/docs/flatlist/
下面是效果图:
ios效果图
android效果图
总体思路就是:就是计算屏幕高度,然后减去导航的头部,根据列表高度计算出每页的个数,然后向上取整。这样做的目的是:防止不满屏状态下的,onEndReached函数的主动触发。
方法实现:
1 2 3 4 5 6 7 | //满屏页面判断 fullScreenJusting(ItemHeight) { const screnHeight = screnInfo.size.height; //屏幕高度 //计算列表个数 const listNum = (screnHeight - 40) / ItemHeight; return Math.ceil(listNum); } |
下拉刷新用的是 RefreshControl
官网地址:https://reactnative.cn/docs/refreshcontrol/#progressbackgroundcolor
具体代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | import React, { Component } from 'react'; import { View, Text, Image, StyleSheet, FlatList, RefreshControl, ActivityIndicator, } from 'react-native'; import { SafeAreaView } from 'react-navigation'; import screnInfo from '../utils/View'; import BaseStyle from '../constants/Style'; import { QUESTION_LIST } from '../constants/Api'; import { form_req } from '../utils/Request'; export default class TestScreen extends Component { constructor(props) { super(props); this.state = { data: [ ], refreshing: false, fresh: true, animating: true, nomore: false, pageSize: 0, pageNumber: 1, }; } componentDidMount() { //初始化的时候要判断长度 控制上拉加载 const ListNums = this.fullScreenJusting(50); this.setState({ pageSize: ListNums }) this.onEndReachedCalled = false; this.getOrderList(ListNums, 1, true); } //满屏页面判断 fullScreenJusting(ItemHeight) { const screnHeight = screnInfo.size.height; //屏幕高度 //计算列表个数 const listNum = (screnHeight - 40) / ItemHeight; return Math.ceil(listNum); } getOrderList(ListNums, pageNumber, fresh) { let nomore; form_req(QUESTION_LIST, { page: pageNumber, perpage: ListNums, }).then(res => { if (res.code == 200) { const item = res.data; if (item.length < ListNums) { nomore = true } else { nomore = false } if (fresh) { this.setState({ data: item, nomore: nomore }) } else { this.setState({ data: this.state.data.concat(item), nomore: nomore, }) } // this.onEndReachedCalledDuringMomentum = true; } else { } }); } renderItem = item => { return ( <View style={styles.item} key={item.id}> <Text>{item.name}</Text> </View> ); }; //列表线 ItemSeparatorComponent = () => { return <View style={styles.baseLine} />; }; //头部 ListHeaderComponent = () => { }; //尾部 ListFooterComponent = () => { return ( <View style={styles.bottomfoot}> { this.state.data.length != 0 ? this.state.nomore ? ( <Text style={styles.footText}>- 我是有底线的 -</Text> ) : ( <View style={styles.activeLoad}> <ActivityIndicator size="small" animating={this.state.animating} /> <Text style={[styles.footText, styles.ml]}>加载更多...</Text> </View> ) : null } </View> ); }; //为空时 ListEmptyComponent() { return ( <View style={styles.noListView}> {/* <Image style={styles.noListImage} source={require('../images/status/order_no_record.png')} /> */} <Text style={styles.NoListText}>暂无订单</Text> </View> ); } _keyExtractor = (item,index) => item.id; _onEndReached = () => { if (!this.state.nomore && this.onEndReachedCalled ) { this.getOrderList(this.state.pageSize, ++this.state.pageNumber, false); } this.onEndReachedCalled=true; }; _onRefresh() { this.setState({ nomore: false, pageNumber: 1 }, () => { this.getOrderList(this.state.pageSize, 1, true); }) } render() { return ( <SafeAreaView style={BaseStyle.flex}> <View style={styles.listConten}> <FlatList data={this.state.data} keyExtractor={this._keyExtractor} onEndReached={this._onEndReached} refreshing={true} renderItem={({ item }) => this.renderItem(item)} ItemSeparatorComponent={this.ItemSeparatorComponent} ListEmptyComponent={this.ListEmptyComponent} ListFooterComponent={this.ListFooterComponent} onEndReachedThreshold={0.1} refreshControl={ <RefreshControl refreshing={this.state.refreshing} colors={['#ff0000', '#00ff00', '#0000ff']} progressBackgroundColor={"#ffffff"} onRefresh={() => { this._onRefresh(); }} /> } /> </View> </SafeAreaView> ); } } const styles = StyleSheet.create({ listConten: { flex: 1, backgroundColor: '#ffffff', }, item: { flexDirection: 'row', justifyContent: 'center', alignItems: "center", backgroundColor: '#ffffff', height: 50, }, baseLine: { width: screnInfo.size.width, height: 1, backgroundColor: '#eeeeee', }, noListView: { width: screnInfo.size.width, height: screnInfo.size.height - 140, justifyContent: 'center', alignItems: 'center', }, NoListText: { marginTop: 15, fontSize: 18, color: '#999999', }, noListImage: { width: 130, height: 140, }, bottomfoot: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', padding: 10, }, footText: { marginTop: 5, fontSize: 12, color: '#999999', }, activeLoad: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, ml: { marginLeft: 10, }, }); |
这里的坑就是:当初始化进来页面的时候 上拉会主动触发,所以这里加了一个开关 this.onEndReachedCalled = false; 初始化给一个false 当触发了 设为true,放在调取接口之后