skip to Main Content

I have a horizontal ScrollView at the top of the screen. Underneath that, I have a vertical ScrollView that fades out. I have now moved the faded vertical scrollView to overlap the horizontal scrollView at the top of the screen. The issue is, the vertical scrollView now blocks the horizontal one from being able to be touched.

When there is no content from the vertical one blocking the horizontal one, how can I enable touch on the horizontal scrollView?

Reproducible Example ready to go on snack.io
~ In this example, I want to be able to interact with the green cards, when the orange cards are not overtop of them.

Edit

Any implementation where the vertical scrollView fades out on top of the screen is satisfactory, it doesn’t have to be my specific fadedView(MaskedElement/View) component. I originally had it working without the fadedView. I set overflow to visible on the vertical scrollView, and it worked just fine, being able to touch the horizontal scrollView when the overflow wasn’t overlapping, and couldn’t touch the horizontal view when the overflow was overlapping. When looking for a way to make the vertical ScrollView fade out on the top of the screen, overflow wasn’t enough.

Some of the code here as well:

App.js

 <SafeAreaView style={styles.container}>
    <View style={{height: 200, position: 'absolute'}}>
      <ScrollView 
        horizontal 
        style={{height: 200, }}
      >
        <View style={{flexDirection: 'row'}}>
          <View style={styles.cardStyles}>  
              <Text>item 1</Text>
          </View>
            <View style={styles.cardStyles}>  
              <Text>item 2</Text>
          </View>
            <View style={styles.cardStyles}>  
              <Text>item 3</Text>
          </View>
        </View>
      </ScrollView>  
    </View>

    <View style={{flex: 1, marginTop: 10}}>
      <MaskedView element={<MaskedElement />}>
        <View style={{top: 100, }}>
          <VerticalScrollView />
        </View>
      </MaskedView>
    </View>
    
 </SafeAreaView>
);

VerticalScrollView.js

  <View style={{flex: 1}}>
    <ScrollView style={{overflow: 'visible'}}>      
      <View style={styles.cardStyles}>  
        <Text>item 1</Text>
      </View>
       <View style={styles.cardStyles}>  
        <Text>item 2</Text>
      </View>
      <View style={styles.cardStyles}>  
        <Text>item 3</Text>
      </View>
      <View style={styles.cardStyles}>  
         Text>item 4</Text>
      </View>
        <View style={styles.cardStyles}>  
         Text>item 5</Text>
      </View>
    </ScrollView>
  </View>

MaskedView.js

export default ({element, children}) => <MaskedView
 style={styles.container}
 maskElement={element}
>
 {children}
</MaskedView>

2

Answers


  1. Just write like the following:

    • Write the MaskedView component like this:

      import React from 'react';
      import { StyleSheet } from 'react-native';
      import MaskedView from '@react-native-community/masked-view';
      
      export default ({element, children}) => <MaskedView
        style={styles.container}
        maskElement={element}
      >
        {children}
      </MaskedView>
      
      const styles = StyleSheet.create({
       container: {
        flex: 1, 
        flexDirection: 'row', 
        height: '100%',
        position: 'relative', // <== Add this line
       }
      });
      
    • Then write your main App.js file like this:

      import React from 'react';
      import {
        SafeAreaView, View, StyleSheet, ScrollView, Text
      } from 'react-native';
      import MaskedView from './maskedView';
      import MaskedElement from './maskedElement';
      import VerticalScrollView from './VerticalScrollView';
      
      // changing marginTop on line 30 to 100, you can see you are able to scroll the green cards horizontally 
      // How can I scroll the green cards horizontally when the content of the VerticalScrollView is not covering it?
      
      export default () => (
        <SafeAreaView style={styles.container}>
          <View style={{flex: 1, marginTop: 10, borderWidth: 1, borderColor: 'blue'}}>
            <MaskedView element={<MaskedElement />}>
              <View style={{height: 200, position: 'absolute', borderWidth: 1, borderColor: 'red'}}>
                <ScrollView horizontal style={{height: 200, }}>
                  <View style={{flexDirection: 'row'}}>
                    <View style={{height: 200, width: 300, backgroundColor: 'green', padding: 10, justifyContent: 'center', alignItems: 'center'}}>
                      <Text>item 1</Text>
                    </View>
                    <View style={{height: 200, width: 300, backgroundColor: 'green', padding: 10, justifyContent: 'center', alignItems: 'center'}}>
                      <Text>item 2</Text>
                    </View>
                    <View style={{height: 200, width: 300, backgroundColor: 'green', padding: 10, justifyContent: 'center', alignItems: 'center'}}>
                      <Text>item 3</Text>
                    </View>
                  </View>
                </ScrollView>
              </View>
              <View style={{top: 100, }}>
                <VerticalScrollView />
              </View>
            </MaskedView>
          </View>
      
        </SafeAreaView>
      );
      var styles = StyleSheet.create({
        container: {
          flex: 1,
          backgroundColor: 'pink'
        },
      });
      

    TL;DR: Put the horizontal inside the MaskedView, Or something like this.

    Login or Signup to reply.
  2. To ensure that the vertical ScrollView does not obstruct touch events for the horizontal ScrollView when it does not overlap it in order to resolve this problem. We can use the pointer Events property to accomplish this. If there is no content obstructing the horizontal ScrollView, that guarantee that touch events flow through the view containing the vertical ScrollView by setting pointerEvents to ‘box-none’. These only functions, though, if the overlying material is transparent.

    PointerEvents="box-none" is the explanation. In other words, touch events can now flow through the vertical ScrollView’s container unless something (such a view or other element) is obstructing the space. Touch events are blocked by overlapping vertical scroll content; when there is no overlap, the touch events flow through to the horizontal scroll.

    zIndex on Horizontal ScrollView: To guarantee that the horizontal scroll is presented above any other content that may occur below it, I set zIndex: 1 on the View that contains it. This is useful when the vertical scroll’s content doesn’t overlap.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search