Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronously scroll two components at once

I have an app where a timetable is displayed.

When the right ScrollView containing the schedule is scrolled, I want the left ScrollView containing the times to scroll too.

<ScrollView
    ref={'leftScroll'} />

<ScrollView
    ref={'rightScroll'}
    scrollEventThrottle={1}
    onScroll={(e) => this.refs.leftScroll.scrollTo({y: e.nativeEvent.contentOffset.y)}
    onMomentumScroll={(e) => this.refs.leftScroll.scrollTo({y: e.nativeEvent.contentOffset.y)} />

We've managed to scroll it in this way, but it is slow and choppy. Is there a way to completely synchronize the scroll of these two ScrollViews?

The reason for this design is that the times need to be fixed to the left of the screen at all times, and the rooms need to be fixed at the top at all times, and these need to scroll in accordance to the scrolling in the schedule.

like image 521
Naoto Ida Avatar asked Dec 06 '22 17:12

Naoto Ida


1 Answers

I have a similar requirement like you describe - ScrollView with times on left and ScrollView with some information on right.

I was able to get the smooth scrolling to work in react-native with a small change to your code above (though I am not using onMomentumScroll). In the docs they mention an animated attribute on the scrollTo method: https://facebook.github.io/react-native/docs/scrollview.html#scrollto

onScroll={(e) => this.refs.timeScroll.scrollTo({y: e.nativeEvent.contentOffset.y, animated: false})}

Important to note that scrollEventThrottle={16} is required to otherwise the scrolling again is choppy. React-Native docs mention that values 1-16 are not noticeable - and so to use 16.

Edit:

I thought i'd come and give an update to this. My above solution worked to an extent, however it still has the smallest delay that ends up being noticeable.

In the end I ended up implementing Animated as it uses native only.

Define:

const yOffset = new Animated.Value(0);
const onScroll = Animated.event(
  [{ nativeEvent: { contentOffset: { y: yOffset } } }],
  { useNativeDriver: true }
);

Create Method:

viewTranslate() {
    return {
      transform: [{
        translateY: yOffset.interpolate({
          inputRange: [0,1],
          outputRange: [1,0]
        })
      }]
    };
  }

Assign style to Animated.View:

<Animated.View style={this.viewTranslate()>...</Animated.View>

Assign event to Animated.ScrollView:

<Animated.ScrollView scrollEventThrottle={1} onScroll={onScroll}>...</Animated.ScrollView>
like image 144
adam_ Avatar answered Jan 03 '23 13:01

adam_