I'm developing a TimeLine
component. There are Views
list inside horizontal ScrollView
that represents half an hour blocks. And I have a Component called TimeRangeSelector
, which I use to select a range of time in TimeLine
ScrollView
. So while I scroll the ScrollView
I need to move the TimeRangeSelector
in parallel without any lag. Below is the TimeLine
component. You can see the 30mins blocks are filled inside ScrollView
. The yellow color one is the TimeRangeSelector
which is a Animated.View. And the left position of the TimeRangeSelector
is set using the scroll position. Each time ScrollView
moves im setting the state as below.
<ScrollView
horizontal={true}
onScroll={this.onScrollFunc}
>
{timelineElements}
</ScrollView>
onScrollFunc = (event, gesture) => {
this.setState({
contentOffsetX: event.nativeEvent.contentOffset.x,
scrollStopped: false
});
};
And Im passing the scrollBarPosition as props to the TimeRangeSelector and setting its left position style as shown in below code
<TimeRangeSelector
scrollBarPosition={this.state.contentOffsetX}
/>
let styles= [
{
position: "absolute",
left: this.props.scrollBarPosition,
backgroundColor: backgroundColor,
marginTop: 20,
marginLeft: 1,
width: this.state.selectionWidth,
height: 100
}
];
But the issue is when I scroll the ScrollView
the TimeRangeSelector
moves with it, but it has a delay.. when I scroll faster the distance between where it should be and where it is, is becoming high. Can anyone give me some ideas according to your knowledge.
My assumption: According to my understanding, I think the lag is because of it takes several instances to reach the setState
in and set the ScrollBarPosition
as below steps.
ScrollView
moved 1 frame.ScrollView
fires theonScroll
function and emmits the event with new x point.- Then in the
onScroll
function it sets the State.
As I understand it takes some time to happen all these steps from JavaScript thread all the way to Native Thread and come back to JS thread again.
You should use something like
const onScroll = Animated.event([{ nativeEvent: { contentOffset: { x: animatedValue } } }], { useNativeDriver: true });
withconst animatedValue = new Animated.Value(0)
. This way the animation is only done on the native level without going back and forth through the JS thread.This animated value can only be used effectively with opacity and transform style properties, but it should help you with your problem.
You can read more about this, in this awesome article.