Skip to content

Commit e3f1567

Browse files
committed
全自动FlatList
1 parent 39903ef commit e3f1567

File tree

3 files changed

+354
-4
lines changed

3 files changed

+354
-4
lines changed

README.md

+45-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,48 @@
11
# MyRNComponents
2-
稍稍React Native项目中手写的简单组件,类似:跑马灯,全局悬浮窗
2+
稍微整理了下React Native项目中手写的简单组件,类似:跑马灯,全局悬浮窗,全自动FlatList
33

4-
## 效果图
4+
## 部分效果图
55
![image](https://github.com/lxp-git/MyRNComponents/raw/master/src/resources/images/gifs/2018-05-07_09.36.08.gif)
6+
7+
## 全自动FlatList
8+
一个思路,自动管理页码,只需要告诉他如何fetchData以及如何处理page,limit字段
9+
10+
```
11+
<AutoFlatList
12+
data={newsList}
13+
renderItem={({item}) => (
14+
<Touchable
15+
style={{
16+
flexDirection: 'row',
17+
width: '100%',
18+
padding: horizontalSpace,
19+
backgroundColor:white
20+
}}
21+
22+
onPress={()=>{
23+
this.props.dispatch(goNewsDetails(item))
24+
}}
25+
>
26+
<View style={{flex:1}}>
27+
<Text style={{fontSize: fontSizeTitle}}>{item.title}</Text>
28+
<View style={{flexDirection: 'row', marginTop: verticalSpace}}>
29+
<Text style={{fontSize: 12}}>{item.from}</Text>
30+
<Text style={{fontSize: 12, marginLeft: horizontalSpace}}>{item.cnum}</Text>
31+
</View>
32+
</View>
33+
<Image
34+
style={{
35+
width: 88,
36+
height: 88-28,
37+
}}
38+
source={{uri: item.banner}}
39+
/>
40+
</Touchable>
41+
)}
42+
fetchData={(data) => this.props.dispatch(createAction('news/getList')({
43+
mid: 1046,
44+
page: data.page,
45+
limit: data.limit,
46+
}))}
47+
/>
48+
```

src/App.js

+42-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66

77
import React, { Component } from 'react';
88
import {
9+
Image,
910
Platform,
1011
StyleSheet,
11-
Text,
12+
Text, Touchable,
1213
View
13-
} from 'react-native';
14+
} from 'react-native'
1415
import StepMarqueeView, { HEIGHT, LENGTH } from './components/StepMarqueeView'
1516
import CustomService from './components/CustomService'
17+
import AutoFlatList from './components/AutoFlatList'
1618

1719
type Props = {};
1820

@@ -96,6 +98,44 @@ export default class App extends Component<Props> {
9698
</Text>}
9799

98100

101+
<AutoFlatList
102+
data={[]}
103+
renderItem={({item}) => (
104+
<Touchable
105+
style={{
106+
flexDirection: 'row',
107+
width: '100%',
108+
padding: 16,
109+
backgroundColor:'white'
110+
}}
111+
112+
onPress={()=>{
113+
this.props.dispatch(goNewsDetails(item))
114+
}}
115+
>
116+
<View style={{flex:1}}>
117+
<Text style={{fontSize: 17}}>{item.title}</Text>
118+
<View style={{flexDirection: 'row', marginTop: '16'}}>
119+
<Text style={{fontSize: 12}}>{item.from}</Text>
120+
<Text style={{fontSize: 12, marginLeft: '16'}}>{item.cnum}</Text>
121+
</View>
122+
</View>
123+
<Image
124+
style={{
125+
width: 88,
126+
height: 88-28,
127+
}}
128+
source={{uri: item.banner}}
129+
/>
130+
</Touchable>
131+
)}
132+
fetchData={(data) => this.props.dispatch(createAction('news/getList')({
133+
mid: 1046,
134+
page: data.page,
135+
limit: data.limit,
136+
}))}
137+
keyExtractor = {(item, index) => item.nid}
138+
/>
99139

100140
</View>
101141
);

src/components/AutoFlatList.js

+267
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
/**
2+
* 全自动flatlist,就是那种要多自动就有多自动的那种
3+
*/
4+
5+
6+
import React, { Component } from 'react'
7+
import { View, Text, StyleSheet, FlatList, ActivityIndicator, TouchableOpacity, ViewPropTypes } from 'react-native'
8+
import { borderColor } from '../resources/themes/customize/colors'
9+
10+
export const RefreshState = {
11+
Idle: 0,
12+
HeaderRefreshing: 1,
13+
FooterRefreshing: 2,
14+
NoMoreData: 3,
15+
Failure: 4,
16+
EmptyData: 5,
17+
}
18+
19+
type Props = {
20+
refreshState: number,
21+
onHeaderRefresh: Function,
22+
onFooterRefresh?: Function,
23+
data: Array<any>,
24+
25+
footerContainerStyle?: ViewPropTypes.style,
26+
footerTextStyle?: ViewPropTypes.style,
27+
28+
listRef?: any,
29+
30+
footerRefreshingText?: string,
31+
footerFailureText?: string,
32+
footerNoMoreDataText?: string,
33+
footerEmptyDataText?: string,
34+
35+
/**
36+
* 渲染条目的方法
37+
*/
38+
renderItem: Function,
39+
40+
/**
41+
* 获取数据的方式,
42+
*
43+
* onRefresh 和 onEndReached 会带上对应的参数(比如:页码)调用该方法
44+
*/
45+
fetchData: Function,
46+
}
47+
48+
type State = {
49+
/**
50+
* 最终显示的数据
51+
*/
52+
finalData: Array
53+
}
54+
55+
class AutoFlatList extends Component<Props, State> {
56+
static defaultProps = {
57+
footerRefreshingText: '数据加载中…',
58+
footerFailureText: '点击重新加载',
59+
footerNoMoreDataText: '已加载全部数据',
60+
footerEmptyDataText: '暂时没有相关数据',
61+
}
62+
63+
constructor (props) {
64+
super(props)
65+
this.state = {
66+
finalData: props.data,
67+
refreshState: RefreshState.HeaderRefreshing,
68+
page: 1,
69+
limit: 10,
70+
}
71+
}
72+
73+
componentDidMount () {
74+
// setTimeout(() => this.props.fetchData && this.props.fetchData({
75+
// page: this.state.page,
76+
// limit: this.state.limit,
77+
// }), 600)
78+
console.log('this.props.fetchData=',this.props.fetchData)
79+
this.props.fetchData && this.props.fetchData({
80+
page: this.state.page,
81+
limit: this.state.limit,
82+
})
83+
84+
}
85+
86+
componentWillReceiveProps (nextProps: Props) {
87+
88+
if (nextProps.data !== this.props.data){
89+
if (nextProps.data.length > 0) {
90+
// 如果当前返回的有数据
91+
if (this.state.page === 1) {
92+
// 第一次加载或者是刷新
93+
this.setState({
94+
finalData: nextProps.data,
95+
refreshState: RefreshState.Idle,
96+
})
97+
} else {
98+
// 上拉加载更多
99+
this.setState({
100+
finalData: this.state.finalData.concat(nextProps.data),
101+
refreshState: RefreshState.Idle,
102+
})
103+
}
104+
} else {
105+
// 如果当前返回的没有数据
106+
if (this.state.page === 1) {
107+
// 当前界面没有数据
108+
this.setState({
109+
finalData: [],
110+
refreshState: RefreshState.EmptyData,
111+
})
112+
} else {
113+
// 没有更多的数据了
114+
this.setState({
115+
refreshState: RefreshState.NoMoreData,
116+
})
117+
}
118+
}
119+
}
120+
121+
}
122+
123+
shouldComponentUpdate (nextProps, nextState) {
124+
console.log('this.state === nextState',this.state === nextState);
125+
if (this.state === nextState) {
126+
return false
127+
} else {
128+
return true
129+
}
130+
}
131+
132+
// componentDidUpdate (prevProps: Props, prevState: State) {
133+
//
134+
// }
135+
136+
onRefresh = () => {
137+
this.setState({
138+
refreshState: RefreshState.HeaderRefreshing,
139+
page: 1,
140+
}, () => {
141+
this.props.fetchData && this.props.fetchData({
142+
page: this.state.page,
143+
limit: this.state.limit,
144+
})
145+
})
146+
}
147+
148+
onEndReached = (info: { distanceFromEnd: number }) => {
149+
// console.log('refreshState == '+)
150+
if (this.state.refreshState !== RefreshState.Idle) {
151+
return
152+
}
153+
this.setState({
154+
refreshState: RefreshState.FooterRefreshing,
155+
page: this.state.page + 1,
156+
}, () => {
157+
this.props.fetchData && this.props.fetchData({
158+
page: this.state.page,
159+
limit: this.state.limit,
160+
})
161+
})
162+
}
163+
164+
keyExtractor = (item, index) => item.id
165+
166+
render () {
167+
const { renderItem, data, fetchData, ...rest} = this.props
168+
169+
return (
170+
<FlatList
171+
ref={this.props.listRef}
172+
onEndReached={this.onEndReached}
173+
onRefresh={this.onRefresh}
174+
refreshing={this.state.refreshState === RefreshState.HeaderRefreshing}
175+
ListFooterComponent={this.renderFooter}
176+
onEndReachedThreshold={0.1}
177+
renderItem={renderItem}
178+
keyExtractor={this.keyExtractor}
179+
ItemSeparatorComponent={()=>(
180+
<View style={{backgroundColor:borderColor,height: 1,width: '100%'}}/>
181+
)}
182+
183+
{ ...rest }
184+
185+
data={this.state.finalData}
186+
/>
187+
)
188+
}
189+
190+
renderFooter = () => {
191+
let footer = null
192+
193+
const footerContainerStyle = [styles.footerContainer, this.props.footerContainerStyle]
194+
const footerTextStyle = [styles.footerText, this.props.footerTextStyle]
195+
const {
196+
footerRefreshingText, footerFailureText, footerNoMoreDataText, footerEmptyDataText,
197+
} = this.props
198+
199+
switch (this.state.refreshState) {
200+
case RefreshState.Idle:
201+
footer = (<View style={footerContainerStyle}/>)
202+
break
203+
case RefreshState.Failure: {
204+
footer = (
205+
<TouchableOpacity
206+
style={footerContainerStyle}
207+
onPress={() => {
208+
this.props.onFooterRefresh && this.props.onFooterRefresh(RefreshState.FooterRefreshing)
209+
}}
210+
>
211+
<Text style={footerTextStyle}>{footerFailureText}</Text>
212+
</TouchableOpacity>
213+
)
214+
break
215+
}
216+
case RefreshState.EmptyData: {
217+
footer = (
218+
<TouchableOpacity
219+
style={footerContainerStyle}
220+
onPress={() => {
221+
this.props.onFooterRefresh && this.props.onFooterRefresh(RefreshState.FooterRefreshing)
222+
}}
223+
>
224+
<Text style={footerTextStyle}>{footerEmptyDataText}</Text>
225+
</TouchableOpacity>
226+
)
227+
break
228+
}
229+
case RefreshState.FooterRefreshing: {
230+
footer = (
231+
<View style={footerContainerStyle}>
232+
<ActivityIndicator size="small" color="#888888"/>
233+
<Text style={[footerTextStyle, {marginLeft: 7}]}>{footerRefreshingText}</Text>
234+
</View>
235+
)
236+
break
237+
}
238+
case RefreshState.NoMoreData: {
239+
footer = (
240+
<View style={footerContainerStyle}>
241+
<Text style={footerTextStyle}>{footerNoMoreDataText}</Text>
242+
</View>
243+
)
244+
break
245+
}
246+
}
247+
248+
return footer
249+
}
250+
}
251+
252+
const styles = StyleSheet.create({
253+
footerContainer: {
254+
flex: 1,
255+
flexDirection: 'row',
256+
justifyContent: 'center',
257+
alignItems: 'center',
258+
padding: 10,
259+
height: 44,
260+
},
261+
footerText: {
262+
fontSize: 14,
263+
color: '#555555',
264+
},
265+
})
266+
267+
export default AutoFlatList

0 commit comments

Comments
 (0)