Issue
I've created a FilterModal component that consists of the generic modal with a scrollView as the inside content. I'm having issues where whenever I swipe on the main modal, swiping will control the modal (as expected) but whenever I swipe anywhere in the scroll view it doesn't propagate properly and will still control the modal instead of the scrollView. It's not until I click on a button then swipe from that will it swipe inside the scrollView.
The main FilterModal.tsx file is as below.
export default function FilterModal({
isVisible,
setIsVisible,
}: FilterModalProps) {
const [scrollOffset, setScrollOffset] = useState(0);
const scrollViewRef = useRef<ScrollView>(null);
const handleOnScroll = (event: any) => {
setScrollOffset(event.nativeEvent.contentOffset.y);
};
const handleScrollTo = (p: any) => {
if (scrollViewRef.current) {
scrollViewRef.current.scrollTo(p);
}
};
return (
<Modal
isVisible={isVisible}
onSwipeComplete={() => setIsVisible(false)}
swipeDirection={['down']}
scrollTo={handleScrollTo}
scrollOffset={scrollOffset}
scrollOffsetMax={300 - screenHeight}
propagateSwipe={true}
style={styles.modal}>
<FilterModalContent
scrollViewRef={scrollViewRef}
handleOnScroll={handleOnScroll}
/>
</Modal>
);
}
const styles = StyleSheet.create({
modal: {
justifyContent: 'flex-end',
margin: 0,
},
});
Then the FilterModalContent.tsx consists of the below:
export default function FilterModalContent({
scrollViewRef,
handleOnScroll,
}: FilterModalContentProps) {
const testAccordionHeaders = ['Test1', 'test2', 'asdadsa'];
return (
<View style={styles.scrollableModal}>
<View style={styles.headerContainer}>
<View style={styles.topRectContainer} />
<Text style={styles.headerText}>Filters</Text>
</View>
<ScrollView
ref={scrollViewRef}
onScroll={handleOnScroll}
style={styles.scrollViewContainer}
contentContainerStyle={styles.scrollViewContent}
scrollEventThrottle={16}>
<View style={styles.dropdownContainer}>
<FilterModalRow header="On Special" checkbox />
<FilterModalRow
header="Brand"
accordion
accordionHeaders={testAccordionHeaders}
/>
<FilterModalRow
header="Allergen"
accordion
accordionHeaders={testAccordionHeaders}
/>
<FilterModalRow
header="Dietary"
accordion
accordionHeaders={testAccordionHeaders}
/>
</View>
</ScrollView>
<View style={styles.buttonContainer}>
<View style={styles.bottomButtons}>
<View style={styles.singularButtonContainer}>
<CustomButton
backgroundColor="#D9D9D9"
text="Reset"
onPress={() => {}}
/>
</View>
<View style={styles.singularButtonContainer}>
<CustomButton text="Apply Filters" onPress={() => {}} />
</View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
scrollableModal: {
height: screenHeight,
backgroundColor: '#EBE9E9',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
overflow: 'hidden',
},
headerContainer: {
alignItems: 'center',
width: '100%',
borderBottomColor: '#D9D9D9',
paddingBottom: 5,
borderBottomWidth: 1,
},
topRectContainer: {
height: 10,
width: '30%',
backgroundColor: '#D9D9D9',
borderRadius: 10,
marginTop: 10,
},
headerText: {
fontWeight: 'bold',
color: 'black',
fontSize: 18,
marginTop: 10,
},
scrollViewContainer: {
flex: 1,
},
scrollViewContent: {
flexGrow: 1,
alignItems: 'center',
},
scrollableModalContent1: {
alignItems: 'center',
justifyContent: 'flex-start',
width: '100%',
marginBottom: 20,
},
dropdownContainer: {
width: '100%',
alignItems: 'center',
justifyContent: 'flex-start',
},
buttonContainer: {
height: 60,
alignItems: 'center',
width: '100%',
justifyContent: 'flex-start',
paddingBottom: 10,
borderTopColor: '#D9D9D9',
paddingTop: 10,
borderTopWidth: 1,
},
headerRow: {
width: '90%',
borderBottomColor: 'black',
borderBottomWidth: 2,
padding: 10,
},
bottomButtons: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '90%',
},
singularButtonContainer: {
width: '40%',
marginBottom: 5,
},
});
I'm able to constantly replicate the issue by once clicking on the header where the 'topRectContainer' view is then trying to swipe inside the scrollView. It will always swipe the modal up and down instead of scrolling inside the scrollView.
PS. Feel free to give me some pointers on code quality as well :)
Solution
I found a fix. Seems a bit hacky but it gets the job done. Inside FilterModalContent (the actual content of the modal) inside ScrollView, add a TouchableOpacity that wraps around all the content.
<View style={styles.scrollableModal}>
<View style={styles.headerContainer}>
<View style={styles.topRectContainer} />
<Text style={styles.headerText}>Filters</Text>
</View>
<ScrollView
ref={scrollViewRef}
onScroll={handleOnScroll}
style={styles.scrollViewContainer}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollViewContent}
scrollEventThrottle={16}>
<TouchableOpacity activeOpacity={1} style={styles.dropdownContainer}>
<FilterModalRow header="On Special" checkbox />
<FilterModalRow
header="Brand"
accordion
accordionHeaders={testAccordionHeaders}
/>
<FilterModalRow
header="Allergen"
accordion
accordionHeaders={testAccordionHeaders}
/>
<FilterModalRow
header="Dietary"
accordion
accordionHeaders={testAccordionHeaders}
/>
</TouchableOpacity>
</ScrollView>
<View style={styles.buttonContainer}>
<View style={styles.bottomButtons}>
<View style={styles.singularButtonContainer}>
<CustomButton
backgroundColor="#D9D9D9"
text="Reset"
onPress={() => {}}
/>
</View>
<View style={styles.singularButtonContainer}>
<CustomButton text="Apply Filters" onPress={() => {}} />
</View>
</View>
</View>
</View>
Note the TouchableOpacity under scrollView and the activeOpacity to remove the opacity change when clicking on the 'TouchableOpacity'.
Answered By - Tom
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.