From 09236ccbe74775359dff14404214b7082e34cc8e Mon Sep 17 00:00:00 2001 From: Mr Speaker Date: Wed, 15 Jul 2015 10:05:13 -0700 Subject: [PATCH] Allow horizontal ListView. Rename height -> size Summary: Infinite scrolling in horizontal ListViews. Rather than just using height and Y offset to determine when to load more rows, it checks `props.horizontal` and switches between width/height and offset X/Y accordingly. This changed required some renaming. However, the only change external to `ListView.js` is exporting `contentSize` instead of `contentHeight` from the `getMetrics()` function. (This is not part of the API, but is used "for perf investigations or analytics" and isn't reference in the repo). I believe this change works as expected (and the xcode tests pass) though it's possible that there may more complexity in this issue that I have overlooked. Closes https://github.com/facebook/react-native/pull/1786 Github Author: Mr Speaker --- .../CustomComponents/ListView/ListView.js | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js index 16faeb100..93ba01f34 100644 --- a/Libraries/CustomComponents/ListView/ListView.js +++ b/Libraries/CustomComponents/ListView/ListView.js @@ -209,7 +209,7 @@ var ListView = React.createClass({ */ getMetrics: function() { return { - contentHeight: this.scrollProperties.contentHeight, + contentLength: this.scrollProperties.contentLength, totalRows: this.props.dataSource.getRowCount(), renderedRows: this.state.curRenderedRowsCount, visibleRows: Object.keys(this._visibleRows).length, @@ -255,9 +255,9 @@ var ListView = React.createClass({ componentWillMount: function() { // this data should never trigger a render pass, so don't put in state this.scrollProperties = { - visibleHeight: null, - contentHeight: null, - offsetY: 0 + visibleLength: null, + contentLength: null, + offset: 0 }; this._childFrames = []; this._visibleRows = {}; @@ -409,12 +409,12 @@ var ListView = React.createClass({ scrollComponent.getInnerViewNode(), React.findNodeHandle(scrollComponent), logError, - this._setScrollContentHeight + this._setScrollContentLength ); RCTUIManager.measureLayoutRelativeToParent( React.findNodeHandle(scrollComponent), logError, - this._setScrollVisibleHeight + this._setScrollVisibleLength ); // RCTScrollViewManager.calculateChildFrames is not available on @@ -426,12 +426,14 @@ var ListView = React.createClass({ ); }, - _setScrollContentHeight: function(left, top, width, height) { - this.scrollProperties.contentHeight = height; + _setScrollContentLength: function(left, top, width, height) { + this.scrollProperties.contentLength = !this.props.horizontal ? + height : width; }, - _setScrollVisibleHeight: function(left, top, width, height) { - this.scrollProperties.visibleHeight = height; + _setScrollVisibleLength: function(left, top, width, height) { + this.scrollProperties.visibleLength = !this.props.horizontal ? + height : width; this._updateVisibleRows(); this._renderMoreRowsIfNeeded(); }, @@ -441,8 +443,8 @@ var ListView = React.createClass({ }, _renderMoreRowsIfNeeded: function() { - if (this.scrollProperties.contentHeight === null || - this.scrollProperties.visibleHeight === null || + if (this.scrollProperties.contentLength === null || + this.scrollProperties.visibleLength === null || this.state.curRenderedRowsCount === this.props.dataSource.getRowCount()) { return; } @@ -472,9 +474,9 @@ var ListView = React.createClass({ }, _getDistanceFromEnd: function(scrollProperties) { - return scrollProperties.contentHeight - - scrollProperties.visibleHeight - - scrollProperties.offsetY; + return scrollProperties.contentLength - + scrollProperties.visibleLength - + scrollProperties.offset; }, _updateVisibleRows: function(updatedFrames) { @@ -486,9 +488,10 @@ var ListView = React.createClass({ this._childFrames[newFrame.index] = merge(newFrame); }); } + var isVertical = !this.props.horizontal; var dataSource = this.props.dataSource; - var visibleTop = this.scrollProperties.offsetY; - var visibleBottom = visibleTop + this.scrollProperties.visibleHeight; + var visibleMin = this.scrollProperties.offset; + var visibleMax = visibleMin + this.scrollProperties.visibleLength; var allRowIDs = dataSource.rowIdentities; var header = this.props.renderHeader && this.props.renderHeader(); @@ -516,9 +519,9 @@ var ListView = React.createClass({ break; } var rowVisible = visibleSection[rowID]; - var top = frame.y; - var bottom = top + frame.height; - if (top > visibleBottom || bottom < visibleTop) { + var min = isVertical ? frame.y : frame.x; + var max = min + (isVertical ? frame.height : frame.width); + if (min > visibleMax || max < visibleMin) { if (rowVisible) { visibilityChanged = true; delete visibleSection[rowID]; @@ -546,16 +549,23 @@ var ListView = React.createClass({ }, _onScroll: function(e) { - this.scrollProperties.visibleHeight = e.nativeEvent.layoutMeasurement.height; - this.scrollProperties.contentHeight = e.nativeEvent.contentSize.height; - this.scrollProperties.offsetY = e.nativeEvent.contentOffset.y; + var isVertical = !this.props.horizontal; + this.scrollProperties.visibleLength = e.nativeEvent.layoutMeasurement[ + isVertical ? 'height' : 'width' + ]; + this.scrollProperties.contentLength = e.nativeEvent.contentSize[ + isVertical ? 'height' : 'width' + ]; + this.scrollProperties.offset = e.nativeEvent.contentOffset[ + isVertical ? 'y' : 'x' + ]; this._updateVisibleRows(e.nativeEvent.updatedChildFrames); var nearEnd = this._getDistanceFromEnd(this.scrollProperties) < this.props.onEndReachedThreshold; if (nearEnd && this.props.onEndReached && - this.scrollProperties.contentHeight !== this._sentEndForContentHeight && + this.scrollProperties.contentLength !== this._sentEndForContentLength && this.state.curRenderedRowsCount === this.props.dataSource.getRowCount()) { - this._sentEndForContentHeight = this.scrollProperties.contentHeight; + this._sentEndForContentLength = this.scrollProperties.contentLength; this.props.onEndReached(e); } else { this._renderMoreRowsIfNeeded();