Reputation: 1015
I'm using React-Native's SectionList
component to implement a list with sticky section headers. I'd like to apply special styling to whichever section header is currently sticky.
I've tried 2 methods to determine which sticky header is currently "sticky," and neither have worked:
onLayout
prop to determine each of their y offsets, and use that in combination with the SectionList
onScroll
event to calculate which section header is currently "sticky".SectionList
's onViewableItemsChanged
prop to figure out which header is currently sticky.Approach #1 doesn't work because the event
object passed to the onLayout
callback only contains the nativeEvent
height
and width
properties.
Approach #2 doesn't work because the onViewableItemsChanged
callback appears to be invoked with inconsistent data (initially, the first section header is marked as viewable (which it is), then, once it becomes "sticky," it is marked as not viewable, and then with further scrolling it is inexplicable marked as viewable again while it is still "sticky" [this final update seems completely arbitrary]).
Anyone know a solution that works?
Upvotes: 5
Views: 1573
Reputation: 318
While you creating stickyHeaderIndices
array in render() method you should create an object first. Where key is index and value is offset of that particular row, eg. { 0: 0, 5: 100, 10: 200 }
constructor(){
super(props);
this.headersRef = {};
this.stickyHeadersObject = {};
this.stickyHeaderVisible = {};
}
createHeadersObject = (data) => {
const obj = {};
for (let i = 0, l = data.length; i < l; i++) {
const row = data[i];
if (row.isHeaderRow) {
obj[i] = row.offset;
}
}
return obj;
};
createHeadersArray = data => Object.keys(data).map(str => parseInt(str, 10))
render() {
const { data } = this.props;
// Expected that data array already has offset:number and isHeaderRow:boolean values
this.stickyHeadersObject = this.createHeadersObject(data);
const stickyIndicesArray = this.createHeadersArray(this.stickyIndicesObject);
const stickyHeaderIndices = { stickyHeaderIndices: stickyIndicesArray };
return (<FlatList
...
onScroll={event => this.onScroll(event.nativeEvent.contentOffset.y)}
{...stickyHeaderIndices}
...
renderItem={({ item, index }) => {
return (
{ // render header row
item.isHeaderRow &&
<HeaderRow
ref={ref => this.headersRef[index] = ref}
/>
}
{ // render regular row
item.isHeaderRow &&
<RegularRow />
}
);
}}
/>)
Then you have to monitor is current offset bigger than your "titleRow"
onScroll = (offset) => {
Object.keys(this.stickyHeadersObject).map((key) => {
this.stickyHeaderVisible[key] = this.stickyHeadersObject[key] <= offset;
return this.headersRef[key] && this.headersRef[key].methodToUpdateStateInParticularHeaderRow(this.stickyHeaderVisible[key]);
});
};
Upvotes: 1