5

I saw that React Native offers nested vertical scroll-views from React Native Nested ScrollView Can`t Scroll on Android Device

The problem is that it doesn't seem to work on nested Horizontal ScrollViews on Android. See this code for an example:

https://snack.expo.io/@harrytravelchime/broken-horizontal-scroll

import React from 'react';
import _ from 'lodash';
import { View, ScrollView, StyleSheet, Text, SafeAreaView } from 'react-native';

export default class App extends React.PureComponent {
  render() {
    return (
      <SafeAreaView style={styles.container}>
        <ScrollView
          style={{ height: '100%', width: '100%' }}
          horizontal
          nestedScrollEnabled
        >
          <View style={{ flexDirection: 'row' }}>
            <ScrollView
              style={{ width: 200, height: '100%' }}
              horizontal
              nestedScrollEnabled
            >
              <View style={{ flexDirection: 'row' }}>
                {_.times(200, n => (
                  <View key={1000 + n} style={{ marginRight: 10 }}>
                    <Text>{1000 + n}</Text>
                  </View>
                ))}
              </View>
            </ScrollView>
            {_.times(200, n => (
              <View key={n} style={{ marginRight: 10 }}>
                <Text>{n}</Text>
              </View>
            ))}
          </View>
        </ScrollView>
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'stretch',
    paddingVertical: 50,
  },
});

On the other hand, the same code except with vertical scrolling totally works: https://snack.expo.io/@harrytravelchime/working-vertical-scroll

Is there a way to make nested horizontal scrolling work?

2
  • Try removing "nestedScrollEnabled" flag from parent ScrollView Commented Aug 31, 2019 at 5:07
  • Having only "nestedScrollEnabled" on just the inner ScrollView still doesn't work. To be comprehensive, I tried enabling nestedScrollEnabled on (1) neither ScrollView, (2) outer ScrollView only, (3) inner ScrollView only, and (4) both ScrollViews Commented Sep 3, 2019 at 15:48

2 Answers 2

7

One solution that I've come up with is to have a TouchableWithoutFeedback that tracks any touch by the user within the inner ScrollView. As soon as it detects a touch, it disables scrolling on the outer ScrollView, which would cause the inner ScrollView to receive events.

The main changes from the above code are:

  1. Added state with outerScrollViewScrollEnabled
  2. When the inner ScrollView is touched via the TouchableWithoutFeedback, change that state
  3. Make the outer ScrollView's scrollEnabled depend on that
import React from "react";
import _ from "lodash";
import {
  View,
  ScrollView,
  StyleSheet,
  Text,
  SafeAreaView,
  TouchableWithoutFeedback
} from "react-native";

interface State {
  outerScrollViewScrollEnabled: boolean;
}

export default class App extends React.PureComponent {
  state = { outerScrollViewScrollEnabled: true };

  handleInnerPressIn = () => this.setState({ outerScrollViewScrollEnabled: false });
  handleInnerPressOut = () => this.setState({ outerScrollViewScrollEnabled: true });

  render() {
    const { outerScrollViewScrollEnabled } = this.state;

    return (
      <SafeAreaView style={styles.container}>
        <ScrollView
          style={{ height: "100%", width: "100%" }}
          horizontal
          scrollEnabled={outerScrollViewScrollEnabled}
        >
          <View style={{ flexDirection: "row" }}>
            <ScrollView style={{ width: 200, height: "100%" }} horizontal>
              <TouchableWithoutFeedback
                onPressIn={this.handleInnerPressIn}
                onPressOut={this.handleInnerPressOut}
              >
                <View style={{ flexDirection: "row" }}>
                  {_.times(200, n => (
                    <View key={1000 + n} style={{ marginRight: 10 }}>
                      <Text>{1000 + n}</Text>
                    </View>
                  ))}
                </View>
              </TouchableWithoutFeedback>
            </ScrollView>
            {_.times(200, n => (
              <View key={n} style={{ marginRight: 10 }}>
                <Text>{n}</Text>
              </View>
            ))}
          </View>
        </ScrollView>
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: "column",
    justifyContent: "center",
    alignItems: "stretch",
    paddingVertical: 50
  }
});
Sign up to request clarification or add additional context in comments.

Comments

6

There is one more easier solution if you are using react-native-gesture-handler

import { ScrollView } from 'react-native'
import { ScrollView as GestureHandlerScrollView } from 'react-native-gesture-handler'

<ScrollView horizontal>
    <GestureHandlerScrollView horizontal />
</ScrollVIew>

I got this answer from react-native github issue

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.