Skip to content

Commit e310b30

Browse files
committed
support for section header
2 parents 5cc349d + 368102a commit e310b30

File tree

5 files changed

+113
-30
lines changed

5 files changed

+113
-30
lines changed

Examples/example_advanced.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ var Example = React.createClass({
2323
* Should be replaced by your own logic
2424
* @param {number} page Requested page to fetch
2525
* @param {function} callback Should pass the rows
26+
* @param {object} options Inform if first load
2627
*/
27-
_onFetch(page = 1, callback) {
28+
_onFetch(page = 1, callback, options) {
2829
setTimeout(() => {
29-
var rows = ['row '+((page - 1) * 3 + 1), 'row '+((page - 1) * 3 + 2), 'row '+((page - 1) * 3 + 3)];
30+
var header = 'Header '+page;
31+
var rows = {};
32+
rows[header] = ['row '+((page - 1) * 3 + 1), 'row '+((page - 1) * 3 + 2), 'row '+((page - 1) * 3 + 3)];
3033
if (page === 3) {
3134
callback(rows, {
3235
allLoaded: true, // the end of the list is reached
@@ -61,6 +64,20 @@ var Example = React.createClass({
6164
</TouchableHighlight>
6265
);
6366
},
67+
68+
/**
69+
* Render a row
70+
* @param {object} rowData Row data
71+
*/
72+
_renderSectionHeaderView(sectionData, sectionID) {
73+
return (
74+
<View style={customStyles.header}>
75+
<Text>
76+
{sectionID}
77+
</Text>
78+
</View>
79+
);
80+
},
6481

6582
/**
6683
* Render the refreshable view when waiting for refresh
@@ -217,6 +234,9 @@ var Example = React.createClass({
217234
emptyView={this._renderEmptyView}
218235

219236
renderSeparator={this._renderSeparatorView}
237+
238+
withSections={true} // enable sections
239+
sectionHeaderView={this._renderSectionHeaderView}
220240
/>
221241
</View>
222242
);
@@ -258,6 +278,10 @@ var customStyles = {
258278
padding: 10,
259279
height: 44,
260280
},
281+
header: {
282+
backgroundColor: '#EEE',
283+
padding: 10,
284+
}
261285
};
262286

263287
var screenStyles = {

Examples/example_simple.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ var Example = React.createClass({
2121
* Should be replaced by your own logic
2222
* @param {number} page Requested page to fetch
2323
* @param {function} callback Should pass the rows
24+
* @param {object} options Inform if first load
2425
*/
25-
_onFetch(page = 1, callback) {
26+
_onFetch(page = 1, callback, options) {
2627
setTimeout(() => {
2728
var rows = ['row '+((page - 1) * 3 + 1), 'row '+((page - 1) * 3 + 2), 'row '+((page - 1) * 3 + 3)];
2829
if (page === 3) {
@@ -70,6 +71,7 @@ var Example = React.createClass({
7071
firstLoader={true} // display a loader for the first fetching
7172
pagination={true} // enable infinite scrolling using touch to load more
7273
refreshable={true} // enable pull-to-refresh for iOS and touch-to-refresh for Android
74+
withSections={false} // enable sections
7375
/>
7476
</View>
7577
);

GiftedListView.js

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ var {
1010
Text
1111
} = React;
1212

13+
// small helper function which merged two objects into one
14+
function MergeRecursive(obj1, obj2) {
15+
for (var p in obj2) {
16+
try {
17+
if ( obj2[p].constructor==Object ) {
18+
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
19+
} else {
20+
obj1[p] = obj2[p];
21+
}
22+
} catch(e) {
23+
obj1[p] = obj2[p];
24+
}
25+
}
26+
return obj1;
27+
}
28+
1329
var GiftedSpinner = require('react-native-gifted-spinner');
1430

1531
var GiftedListView = React.createClass({
@@ -54,7 +70,9 @@ var GiftedListView = React.createClass({
5470
refreshable: true,
5571
refreshableViewHeight: 50,
5672
refreshableDistance: 40,
57-
onFetch(page, callback) { callback([]); },
73+
sectionHeaderView: null,
74+
withSections: false,
75+
onFetch(page, callback, options) { callback([]); },
5876

5977
paginationFetchigView() {
6078
return (
@@ -157,11 +175,9 @@ var GiftedListView = React.createClass({
157175
_setRows(rows) { this._rows = rows; },
158176
_getRows() { return this._rows; },
159177

178+
160179
getInitialState() {
161-
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => {
162-
return r1 !== r2;
163-
}});
164-
180+
165181
if (this.props.refreshable === true && Platform.OS !== 'android') {
166182
this._setY(this.props.refreshableViewHeight);
167183
} else {
@@ -170,26 +186,50 @@ var GiftedListView = React.createClass({
170186

171187
this._setPage(1);
172188
this._setRows([]);
173-
174-
return {
175-
dataSource: ds.cloneWithRows(this._getRows()),
176-
refreshStatus: 'waiting',
177-
paginationStatus: 'firstLoad',
178-
};
189+
190+
var ds = null;
191+
if (this.props.withSections === true) {
192+
ds = new ListView.DataSource({
193+
rowHasChanged: (row1, row2) => row1 !== row2,
194+
sectionHeaderHasChanged: (section1, section2) => section1 !== section2,
195+
});
196+
return {
197+
dataSource: ds.cloneWithRowsAndSections(this._getRows()),
198+
refreshStatus: 'waiting',
199+
paginationStatus: 'firstLoad',
200+
};
201+
} else {
202+
ds = new ListView.DataSource({
203+
rowHasChanged: (row1, row2) => row1 !== row2,
204+
});
205+
return {
206+
dataSource: ds.cloneWithRows(this._getRows()),
207+
refreshStatus: 'waiting',
208+
paginationStatus: 'firstLoad',
209+
};
210+
}
179211
},
180212

181213
componentDidMount() {
182214
this._scrollResponder = this.refs.listview.getScrollResponder();
183-
this.props.onFetch(this._getPage(), this._postRefresh);
215+
this.props.onFetch(this._getPage(), this._postRefresh, {firstLoad: true});
216+
},
217+
218+
setNativeProps(props) {
219+
this.refs.listview.setNativeProps(props);
220+
},
221+
222+
_refresh() {
223+
this._onRefresh({external: true});
184224
},
185225

186-
_onRefresh() {
226+
_onRefresh(options = {}) {
187227
this._scrollResponder.scrollTo(0);
188228
this.setState({
189229
refreshStatus: 'fetching',
190230
});
191231
this._setPage(1);
192-
this.props.onFetch(this._getPage(), this._postRefresh);
232+
this.props.onFetch(this._getPage(), this._postRefresh, options);
193233
},
194234

195235
_postRefresh(rows = [], options = {}) {
@@ -205,22 +245,35 @@ var GiftedListView = React.createClass({
205245
this.setState({
206246
paginationStatus: 'fetching',
207247
});
208-
this.props.onFetch(this._getPage() + 1, this._postPaginate);
248+
this.props.onFetch(this._getPage() + 1, this._postPaginate, {});
209249
},
210250

211251
_postPaginate(rows = [], options = {}) {
212252
this._setPage(this._getPage() + 1);
213-
var concatenatedRows = this._getRows().concat(rows);
214-
this._updateRows(concatenatedRows, options);
253+
var mergedRows = null;
254+
if (this.props.withSections === true) {
255+
mergedRows = MergeRecursive(this._getRows(), rows);
256+
} else {
257+
mergedRows = this._getRows().concat(rows);
258+
}
259+
this._updateRows(mergedRows, options);
215260
},
216261

217262
_updateRows(rows = [], options = {}) {
218263
this._setRows(rows);
219-
this.setState({
220-
dataSource: this.state.dataSource.cloneWithRows(rows),
221-
refreshStatus: 'waiting',
222-
paginationStatus: (options.allLoaded === true ? 'allLoaded' : 'waiting'),
223-
});
264+
if (this.props.withSections === true) {
265+
this.setState({
266+
dataSource: this.state.dataSource.cloneWithRowsAndSections(rows),
267+
refreshStatus: 'waiting',
268+
paginationStatus: (options.allLoaded === true ? 'allLoaded' : 'waiting'),
269+
});
270+
} else {
271+
this.setState({
272+
dataSource: this.state.dataSource.cloneWithRows(rows),
273+
refreshStatus: 'waiting',
274+
paginationStatus: (options.allLoaded === true ? 'allLoaded' : 'waiting'),
275+
});
276+
}
224277
},
225278

226279
_onResponderRelease() {
@@ -264,9 +317,9 @@ var GiftedListView = React.createClass({
264317
},
265318

266319
_renderPaginationView() {
267-
if ((this.state.paginationStatus === 'fetching' && this.props.pagination === true) || this.state.paginationStatus === 'firstLoad' && this.props.firstLoader === true) {
320+
if ((this.state.paginationStatus === 'fetching' && this.props.pagination === true) || (this.state.paginationStatus === 'firstLoad' && this.props.firstLoader === true)) {
268321
return this.props.paginationFetchigView();
269-
} else if (this.state.paginationStatus === 'waiting' && this.props.pagination === true && this._getRows().length > 0) {
322+
} else if (this.state.paginationStatus === 'waiting' && this.props.pagination === true && (this.props.withSections === true || this._getRows().length > 0)) {
270323
return this.props.paginationWaitingView(this._onPaginate);
271324
} else if (this.state.paginationStatus === 'allLoaded' && this.props.pagination === true) {
272325
return this.props.paginationAllLoadedView();
@@ -299,6 +352,7 @@ var GiftedListView = React.createClass({
299352
ref="listview"
300353
dataSource={this.state.dataSource}
301354
renderRow={this.props.rowView}
355+
renderSectionHeader={this.props.sectionHeaderView}
302356
initialListSize={this.props.initialListSize}
303357
renderSeparator={this.props.renderSeparator}
304358

@@ -322,4 +376,4 @@ var GiftedListView = React.createClass({
322376
});
323377

324378

325-
module.exports = GiftedListView;
379+
module.exports = GiftedListView;

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ var Example = React.createClass({
2828
* Should be replaced by your own logic
2929
* @param {number} page Requested page to fetch
3030
* @param {function} callback Should pass the rows
31+
* @param {object} options Inform if first load
3132
*/
32-
_onFetch(page = 1, callback) {
33+
_onFetch(page = 1, callback, options) {
3334
setTimeout(() => {
3435
var rows = ['row '+((page - 1) * 3 + 1), 'row '+((page - 1) * 3 + 2), 'row '+((page - 1) * 3 + 3)];
3536
if (page === 3) {
@@ -77,6 +78,7 @@ var Example = React.createClass({
7778
firstLoader={true} // display a loader for the first fetching
7879
pagination={true} // enable infinite scrolling using touch to load more
7980
refreshable={true} // enable pull-to-refresh for iOS and touch-to-refresh for Android
81+
withSections={false} // enable sections
8082
/>
8183
</View>
8284
);
@@ -117,6 +119,7 @@ var styles = {
117119
- [x] Loader for first display
118120
- [x] Default view when no content to display
119121
- [x] Customizable (see advanced example)
122+
- [x] Support for section header
120123
- [ ] Pull-to-refresh in Android (tried to implement it but it seems that onResponderRelease event is not catchable yet in Android ListView - React-Native 0.13.2)
121124

122125

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-gifted-listview",
3-
"version": "0.0.2",
3+
"version": "0.0.3",
44
"description": "A ListView that embed some recurrents features like pull-to-refresh, infinite scrolling and more for Android and iOS React-Native apps",
55
"main": "GiftedListView.js",
66
"scripts": {

0 commit comments

Comments
 (0)