skip to Main Content

I’ve got a ScrollView nested in an absolute positioned View that is bigger then it’s parent. The scrolling works fine if I press inside that parent, but when I go outside it, it’s not handling the touches. How can I get around this?

enter image description here
I can’t scroll if I touch the screen below the green line.

Code to reproduce:

<View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
  <View style={{width: "80%", height: 150, borderWidth: 1}}>
    <View style={{position: 'absolute', height: 400, width: "80%", backgroundColor: "green", alignSelf: "center"}}>
    <ScrollView>
    <View style={{height: 200, backgroundColor: "red"}} />
    <View style={{height: 200, backgroundColor: "blue"}} />
    <View style={{height: 200, backgroundColor: "yellow"}} />
    </ScrollView>
    </View>
  </View>
</View>

Expo Snack: https://snack.expo.dev/uV88qpP7f (Happens on android)

5

Answers


  1. You can do this

    import * as React from 'react';
    import { Text, View, StyleSheet, ScrollView } from 'react-native';
    import Constants from 'expo-constants';
    
    // You can import from local files
    import AssetExample from './components/AssetExample';
    
    // or any pure javascript modules available in npm
    import { Card } from 'react-native-paper';
    
    export default function App() {
    const customHeight = 400; //change this based on your needs
    
    
    return (
    <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
      <View style={{width: "80%", height: 150, borderWidth: 1}}>
        <View style={{position: 'absolute', height: customHeight, width: "80%", backgroundColor: "green", alignSelf: "center"}}>
        <ScrollView style={{backgroundColor: "grey", height: 600}}>
        <View style={{height: 200, backgroundColor: "red"}} />
        <View style={{height: 200, backgroundColor: "blue"}} />
        <View style={{height: 200, backgroundColor: "yellow"}} />
        </ScrollView>
        </View>
      </View>
    </View>
    );
    }
    
    Login or Signup to reply.
  2. Best way I found was to move the ScrollView outside of the card container and get the top position of the ScrollView by calculating the area of the button and container it’s supposed to be relating to. Sort of how tooltips often function.

    import { useState } from 'react';
    import {
      View,
      StyleSheet,
      Pressable,
      Text,
      ScrollView,
      FlatList,
    } from 'react-native';
    import Constants from 'expo-constants';
    import { Feather } from '@expo/vector-icons';
    
    const data = [
      {
        color: 'red',
      },
      {
        color: 'blue',
      },
      {
        color: 'orange',
      },
      {
        color: 'green',
      },
      {
        color: 'pink',
      },
    ];
    
    export default function App() {
      const [value, setValue] = useState('Press me!');
      const [heightOfButton, setHeightOfButton] = useState(0);
      const [heightOfContainer, setHeightOfContainer] = useState(0);
      const [shouldShow, setShouldShow] = useState(true);
      // android handles the padding a bit strange but I feel like this is close to what you're looking for.
      const scrollPosition = heightOfContainer + 12 + heightOfButton
    
      return (
        <View style={styles.container}>
          <View
            onLayout={(e) =>
              setHeightOfContainer(e.nativeEvent.layout.y)
            }
            style={styles.card}>
            <Pressable
              onLayout={(e) =>
                setHeightOfButton(e.nativeEvent.layout.height)
              }
              onPress={() => setShouldShow(true)}
              style={styles.button}>
              <Text>{value}</Text>
              <Feather name="chevron-down" size={24} />
            </Pressable>
          </View>
          {shouldShow ? (
            <FlatList
              style={{
                position: 'absolute',
                top: scrollPosition,
                height: 400,
                width: '80%',
                backgroundColor: 'green',
                alignSelf: 'center',
              }}
              data={data}
              renderItem={({ item }) => (
                <Pressable
                  onPress={() => {
                    setValue(item.color);
                    setShouldShow(false);
                  }}
                  style={{ height: 200, backgroundColor: item.color }}
                />
              )}
            />
          ) : null}
          {/*<ScrollView 
              style={{ 
                position: 'absolute',
                bottom: height,
                height: 400, 
                width: "80%", 
                backgroundColor: "green", 
                alignSelf: "center"
              }}>
            <View style={{height: 200, backgroundColor: "red"}} />
            <View style={{height: 200, backgroundColor: "blue"}} />
            <View style={{height: 200, backgroundColor: "yellow"}} />
            </ScrollView> */}
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        paddingTop: Constants.statusBarHeight,
        backgroundColor: 'lightblue',
        padding: 8,
      },
      card: {
        backgroundColor: 'white',
        height: '30%',
        borderRadius: 8,
        padding: 12,
      },
      button: {
        width: '100%',
        borderColor: 'black',
        borderRadius: 8,
        borderWidth: 1,
        padding: 12,
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between',
      },
    });
    

    I moved your example to a FlatList as it seems like that was what you were hoping to do in the example.

    Here’s the snack https://snack.expo.dev/@corywritescode/frowning-carrot

    Login or Signup to reply.
  3. Issue is with your approach to design. You can achieve the desire functionality with same design by following code.

    <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
      <View style={{width: "80%"}}>
        <View style={{ height: 150, borderWidth: 1}}/>
        <View style={{position: 'absolute', height: 400, width: "80%", backgroundColor: "green", alignSelf: "center"}}>
        <ScrollView>
        <View style={{height: 200, backgroundColor: "red"}} />
        <View style={{height: 200, backgroundColor: "blue"}} />
        <View style={{height: 200, backgroundColor: "yellow"}} />
        </ScrollView>
        </View>
      </View>
    </View>
    
    Login or Signup to reply.
  4. Demo

    https://snack.expo.dev/bsHCCB1_l

    Try declaring your Box above the scroll view otherwise the touch area below Box won’t work

    ScrollView with Position absolute should be below to Box to make touch in work

    Code

    import { View,ScrollView } from 'react-native';
    
    const Box=()=>{
      return <View style={{ height: 150, borderWidth: 1}} />
    }
    const DropDown=()=>{
      return (
        <View style={{position: 'absolute', height: 400, width: "80%", backgroundColor: "green", alignSelf: "center"}}>
          <ScrollView>
          <View style={{height: 200, backgroundColor: "red"}} />
          <View style={{height: 200, backgroundColor: "blue"}} />
          <View style={{height: 200, backgroundColor: "yellow"}} />
          </ScrollView>
         </View>
      )
    }
    
    export default function App() {
      return (
        <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
          <View style={{width: "80%"}}>
    
            <Box />
    
            <DropDown /> 
    
          </View>
        </View>
      );
    }
    
    
    Login or Signup to reply.
  5. Absolute position style causes this problem. I just remove it and set new style above.

    export default function App() {
      return (
        <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
          <View style={{width: "80%", height: 150, borderWidth: 1, backgroundColor: "green"}}>
            <ScrollView>
            <View style={{height: 70, backgroundColor: "red"}} />
            <View style={{height: 70, backgroundColor: "blue"}} />
            <View style={{height: 70, backgroundColor: "yellow"}} />
            </ScrollView>
          </View>
        </View>
      );
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search