Skip to content

Commit

Permalink
Add scrollToLocation for SectionList
Browse files Browse the repository at this point in the history
Summary:
Basic functionality that takes `itemIndex` and `sectionIndex`

**TestPlan**

Added this to onChangeText:

	this._listRef.getNode().scrollToLocation({itemIndex: 6, sectionIndex: 3, viewOffset: 25});

and saw it scroll to the correct position right under the sticky header.

Reviewed By: bvaughn

Differential Revision: D4821714

fbshipit-source-id: 261e373f9c4af384db5a363df5b0fd9274b1bdfe
  • Loading branch information
sahrens authored and facebook-github-bot committed Apr 4, 2017
1 parent 87bdcbd commit ecf4c48
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 13 deletions.
18 changes: 12 additions & 6 deletions Libraries/Lists/FlatList.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ type DefaultProps = typeof defaultProps;
* }
*
* This is a convenience wrapper around [`<VirtualizedList>`](docs/virtualizedlist.html),
* and thus inherits it's props that aren't explicitly listed here along with the following caveats:
* and thus inherits it's props (as well as those of `ScrollView`) that aren't explicitly listed
* here, along with the following caveats:
*
* - Internal state is not preserved when content scrolls out of the render window. Make sure all
* your data is captured in the item data or external stores like Flux, Redux, or Relay.
Expand Down Expand Up @@ -264,17 +265,22 @@ class FlatList<ItemT> extends React.PureComponent<DefaultProps, Props<ItemT>, vo
/**
* Scrolls to the item at a the specified index such that it is positioned in the viewable area
* such that `viewPosition` 0 places it at the top, 1 at the bottom, and 0.5 centered in the
* middle.
* middle. `viewOffset` is a fixed number of pixels to offset the final target position.
*
* May be janky without `getItemLayout` prop.
* Note: cannot scroll to locations outside the render window without specifying the
* `getItemLayout` prop.
*/
scrollToIndex(params: {animated?: ?boolean, index: number, viewPosition?: number}) {
scrollToIndex(params: {
animated?: ?boolean, index: number, viewOffset?: number, viewPosition?: number,
}) {
this._listRef.scrollToIndex(params);
}

/**
* Requires linear scan through data - use `scrollToIndex` instead if possible. May be janky
* without `getItemLayout` prop.
* Requires linear scan through data - use `scrollToIndex` instead if possible.
*
* Note: cannot scroll to locations outside the render window without specifying the
* `getItemLayout` prop.
*/
scrollToItem(params: {animated?: ?boolean, item: ItemT, viewPosition?: number}) {
this._listRef.scrollToItem(params);
Expand Down
3 changes: 3 additions & 0 deletions Libraries/Lists/MetroListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class MetroListView extends React.Component {
scrollToItem(params: {animated?: ?boolean, item: Item, viewPosition?: number}) {
throw new Error('scrollToItem not supported in legacy ListView.');
}
scrollToLocation() {
throw new Error('scrollToLocation not supported in legacy ListView.');
}
scrollToOffset(params: {animated?: ?boolean, offset: number}) {
const {animated, offset} = params;
this._listRef.scrollTo(
Expand Down
25 changes: 23 additions & 2 deletions Libraries/Lists/SectionList.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ type DefaultProps = typeof defaultProps;
* ]}
* />
*
* This is a convenience wrapper around [`<VirtualizedList>`](/react-native/docs/virtualizedlist.html),
* and thus inherits the following caveats:
* This is a convenience wrapper around [`<VirtualizedList>`](docs/virtualizedlist.html),
* and thus inherits it's props (as well as those of `ScrollView`) that aren't explicitly listed
* here, along with the following caveats:
*
* - Internal state is not preserved when content scrolls out of the render window. Make sure all
* your data is captured in the item data or external stores like Flux, Redux, or Relay.
Expand All @@ -194,6 +195,26 @@ class SectionList<SectionT: SectionBase<any>>
props: Props<SectionT>;
static defaultProps: DefaultProps = defaultProps;

/**
* Scrolls to the item at the specified `sectionIndex` and `itemIndex` (within the section)
* positioned in the viewable area such that `viewPosition` 0 places it at the top (and may be
* covered by a sticky header), 1 at the bottom, and 0.5 centered in the middle. `viewOffset` is a
* fixed number of pixels to offset the final target position, e.g. to compensate for sticky
* headers.
*
* Note: cannot scroll to locations outside the render window without specifying the
* `getItemLayout` prop.
*/
scrollToLocation(params: {
animated?: ?boolean,
itemIndex: number,
sectionIndex: number,
viewOffset?: number,
viewPosition?: number,
}) {
this._wrapperListRef.scrollToLocation(params);
}

/**
* Tells the list an interaction has occured, which should trigger viewability calculations, e.g.
* if `waitForInteractions` is true and the user has not scrolled. This is typically called by
Expand Down
8 changes: 5 additions & 3 deletions Libraries/Lists/VirtualizedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,11 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
}

// scrollToIndex may be janky without getItemLayout prop
scrollToIndex(params: {animated?: ?boolean, index: number, viewPosition?: number}) {
scrollToIndex(params: {
animated?: ?boolean, index: number, viewOffset?: number, viewPosition?: number
}) {
const {data, horizontal, getItemCount, getItemLayout} = this.props;
const {animated, index, viewPosition} = params;
const {animated, index, viewOffset, viewPosition} = params;
invariant(
index >= 0 && index < getItemCount(data),
`scrollToIndex out of range: ${index} vs ${getItemCount(data) - 1}`,
Expand All @@ -194,7 +196,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
const offset = Math.max(
0,
frame.offset - (viewPosition || 0) * (this._scrollMetrics.visibleLength - frame.length),
);
) - (viewOffset || 0);
this._scrollRef.scrollTo(horizontal ? {x: offset, animated} : {y: offset, animated});
}

Expand Down
17 changes: 15 additions & 2 deletions Libraries/Lists/VirtualizedSectionList.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,20 @@ class VirtualizedSectionList<SectionT: SectionBase>
data: [],
};

scrollToLocation(params: {
animated?: ?boolean, itemIndex: number, sectionIndex: number, viewPosition?: number
}) {
let index = params.itemIndex + 1;
for (let ii = 0; ii < params.sectionIndex; ii++) {
index += this.props.sections[ii].data.length + 1;
}
const toIndexParams = {
...params,
index,
};
this._listRef.scrollToIndex(toIndexParams);
}

getListRef(): VirtualizedList {
return this._listRef;
}
Expand Down Expand Up @@ -194,8 +208,7 @@ class VirtualizedSectionList<SectionT: SectionBase>
const {renderSectionHeader} = this.props;
return renderSectionHeader ? renderSectionHeader({section: info.section}) : null;
} else {
const renderItem = info.section.renderItem ||
this.props.renderItem;
const renderItem = info.section.renderItem || this.props.renderItem;
const SeparatorComponent = this._getSeparatorComponent(index, info);
invariant(renderItem, 'no renderItem!');
return (
Expand Down

0 comments on commit ecf4c48

Please sign in to comment.