Reputation: 181
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?
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)
Upvotes: 1
Views: 1720
Reputation: 27
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>
);
}
Upvotes: -3
Reputation: 25363
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
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>
);
}
Upvotes: 1
Reputation: 857
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>
Upvotes: 1
Reputation: 42
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
Upvotes: 0
Reputation: 421
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>
);
}
Upvotes: -1