Skip to content

Commit ece89fd

Browse files
committed
Add renderFooter
1 parent 848f863 commit ece89fd

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ A RefreshControl that works the same way as a ScrollView's refreshControl.
3535
- **renderRow** (function)<br />
3636
`({key, index, data, disabled, active}) => renderable`<br />
3737
Takes a row key, row index, data entry from the data source and its statuses disabled, active and should return a renderable component to be rendered as the row.<br />
38+
- **renderFooter** (function)<br />
39+
`() => renderable`<br />
40+
Renders returned component at the bottom of the list.
3841
- **onChangeOrder** (function)<br />
3942
`(nextOrder) => void`<br />
4043
Called when rows were reordered, takes an array of rows keys of the next rows order.

src/SortableList.js

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default class SortableList extends Component {
2424
refreshControl: PropTypes.element,
2525

2626
renderRow: PropTypes.func.isRequired,
27+
renderFooter: PropTypes.func,
2728

2829
onChangeOrder: PropTypes.func,
2930
onActivateRow: PropTypes.func,
@@ -47,6 +48,8 @@ export default class SortableList extends Component {
4748
*/
4849
_rowsLayouts = [];
4950

51+
_footerLayout = null;
52+
5053
_contentOffset = {x: 0, y: 0};
5154

5255
state = {
@@ -63,7 +66,7 @@ export default class SortableList extends Component {
6366
};
6467

6568
componentDidMount() {
66-
this._onLayoutRows();
69+
this._onUpdateLayouts();
6770
}
6871

6972
componentWillReceiveProps(nextProps) {
@@ -91,7 +94,7 @@ export default class SortableList extends Component {
9194
const {data: prevData} = prevState;
9295

9396
if (data && prevData && !shallowEqual(data, prevData)) {
94-
this._onLayoutRows();
97+
this._onUpdateLayouts();
9598
}
9699
}
97100

@@ -178,6 +181,7 @@ export default class SortableList extends Component {
178181
<View style={innerContainerStyle}>
179182
{this._renderRows()}
180183
</View>
184+
{this._renderFooter()}
181185
</ScrollView>
182186
</View>
183187
);
@@ -252,9 +256,28 @@ export default class SortableList extends Component {
252256
});
253257
}
254258

255-
_onLayoutRows() {
256-
Promise.all([...this._rowsLayouts])
257-
.then((rowsLayouts) => {
259+
_renderFooter() {
260+
if (!this.props.renderFooter || this.props.horizontal) {
261+
return null;
262+
}
263+
264+
const {footerLayout} = this.state;
265+
let resolveLayout;
266+
267+
if (!footerLayout) {
268+
this._footerLayout = new Promise((resolve) => (resolveLayout = resolve));
269+
}
270+
271+
return (
272+
<View onLayout={!footerLayout ? this._onLayoutFooter.bind(this, resolveLayout) : null}>
273+
{this.props.renderFooter()}
274+
</View>
275+
);
276+
}
277+
278+
_onUpdateLayouts() {
279+
Promise.all([this._footerLayout, ...this._rowsLayouts])
280+
.then(([footerLayout, ...rowsLayouts]) => {
258281
// Can get correct container’s layout only after rows’s layouts.
259282
this._container.measure((x, y, width, height, pageX, pageY) => {
260283
const rowsLayoutsByKey = {};
@@ -270,6 +293,7 @@ export default class SortableList extends Component {
270293
this.setState({
271294
containerLayout: {x, y, width, height, pageX, pageY},
272295
rowsLayouts: rowsLayoutsByKey,
296+
footerLayout,
273297
contentHeight,
274298
contentWidth,
275299
}, () => {
@@ -421,25 +445,37 @@ export default class SortableList extends Component {
421445
this._startAutoScroll({
422446
direction: 1,
423447
shouldScroll: () => {
424-
const {contentHeight, contentWidth, containerLayout} = this.state;
448+
const {
449+
contentHeight,
450+
contentWidth,
451+
containerLayout,
452+
footerLayout = {height: 0},
453+
} = this.state;
425454

426455
if (horizontal) {
427456
return this._contentOffset.x < contentWidth - containerLayout.width
428457
} else {
429-
return this._contentOffset.y < contentHeight - containerLayout.height;
458+
return this._contentOffset.y < contentHeight + footerLayout.height - containerLayout.height;
430459
}
431460
},
432461
getScrollStep: (stepIndex) => {
433462
const nextStep = this._getScrollStep(stepIndex);
434-
const {contentHeight, contentWidth, containerLayout} = this.state;
463+
const {
464+
contentHeight,
465+
contentWidth,
466+
containerLayout,
467+
footerLayout = {height: 0},
468+
} = this.state;
435469

436470
if (horizontal) {
437471
return this._contentOffset.x + nextStep > contentWidth - containerLayout.width
438472
? contentWidth - containerLayout.width - this._contentOffset.x
439473
: nextStep;
440474
} else {
441-
return this._contentOffset.y + nextStep > contentHeight - containerLayout.height
442-
? contentHeight - containerLayout.height - this._contentOffset.y
475+
const scrollHeight = contentHeight + footerLayout.height - containerLayout.height;
476+
477+
return this._contentOffset.y + nextStep > scrollHeight
478+
? scrollHeight - this._contentOffset.y
443479
: nextStep;
444480
}
445481
},
@@ -483,6 +519,10 @@ export default class SortableList extends Component {
483519
resolveLayout({rowKey, layout});
484520
}
485521

522+
_onLayoutFooter(resolveLayout, {nativeEvent: {layout}}) {
523+
resolveLayout(layout);
524+
}
525+
486526
_onActivateRow = (rowKey, index, e, gestureState, location) => {
487527
this._activeRowLocation = location;
488528

0 commit comments

Comments
 (0)