Проблема с переключением скролла в модальном окне
После изучения всех чатов решение найдено не было. Текущее поведение: чтобы включить скролл контента на экране, необходимо довести родительский элемент до самого верха и поднять палец. Только после этого скролл контента активируется. Требуется изменить логику: скролл должен включаться при достижении верхней границы экрана родителем во время свайпа, без необходимости поднимать палец.
Текущая реализация и проблема
Сейчас при свайпе вверх родительского элемента и его достижении верхней границы экрана, для включения скролла контента требуется поднять палец. Аналогичная проблема при закрытии: при свайпе вниз нужно поднять палец, чтобы скролл отключился.
Желаемое поведение
- При свайпе вверх родительский элемент поднимается до верхней границы экрана.
- Если свайп продолжается вверх без поднятия пальца, скролл контента должен включиться автоматически.
- При закрытии скролл должен отключаться аналогичным образом - без необходимости поднимать палец.
Текущий код
Используется React Native с компонентами Animated, PanResponder и ScrollView. Ниже приведён фрагмент кода, демонстрирующий логику обработки жестов:
import React, { useEffect, useRef, useState } from 'react';
import {
Modal,
View,
Text,
StyleSheet,
TouchableOpacity,
Animated,
Dimensions,
Image,
PanResponder,
Alert,
ScrollView,
} from 'react-native';
const screenWidth = Dimensions.get('window').width;
const screenHeight = Dimensions.get('window').height;
const INITIAL_POSITION = screenHeight * 0.4;
const Screen1 = ({ navigation }) => {
const [isScrollEnabled, setScrollEnabled] = useState(false);
const [isOverlayVisible, setOverlayVisible] = useState(true);
const slideAnim = useRef(new Animated.Value(INITIAL_POSITION)).current;
const currentPosition = useRef(INITIAL_POSITION);
const scrollViewRef = useRef(null);
useEffect(() => {
slideAnim.setValue(screenHeight);
Animated.timing(slideAnim, {
toValue: INITIAL_POSITION,
duration: 400,
useNativeDriver: true,
}).start();
}, []);
const panResponder = useRef(
PanResponder.create({
onMoveShouldSetPanResponder: (_, gestureState) => {
return Math.abs(gestureState.dy) > 10 && (!isScrollEnabled || gestureState.dy > 0);
},
onPanResponderMove: (_, gestureState) => {
const newPosition = Math.max(0, currentPosition.current + gestureState.dy);
slideAnim.setValue(newPosition);
setOverlayVisible(newPosition < screenHeight * 0.7);
setScrollEnabled(newPosition <= 0);
},
onPanResponderRelease: (_, gestureState) => {
currentPosition.current = slideAnim._value;
if (currentPosition.current > screenHeight * 0.7) {
Animated.timing(slideAnim, {
toValue: screenHeight,
duration: 300,
useNativeDriver: true,
}).start(() => {
navigation.goBack();
});
} else {
Animated.spring(slideAnim, {
toValue: currentPosition.current,
useNativeDriver: true,
}).start();
}
},
})
).current;
const handleScroll = (event) => {
const scrollY = event.nativeEvent.contentOffset.y;
if (scrollY <= 0) {
setScrollEnabled(false);
}
};
return (
<View style={styles.fullScreen}>
{isOverlayVisible && <View style={styles.backgroundOverlay} />}
<Animated.View
style={[styles.overlay, { transform: [{ translateY: slideAnim }] }]}
{...panResponder.panHandlers}
>
<View style={[styles.container, { backgroundColor: '#eee', flex: 1 }]}>
<View style={[styles.section, { backgroundColor: '#eee', height: 200 }]}>
<Text style={[styles.sectionT, { fontSize: 19 }]}>БЛОК ПОД КОТОРЫМ СКОЛЛ</Text>
</View>
<ScrollView
ref={scrollViewRef}
scrollEnabled={isScrollEnabled}
onScroll={handleScroll}
scrollEventThrottle={16}
>
<View style={{ marginRight: 20 }}>
<View style={{ position: 'relative' }}>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
<View style={{ height: 200, margin: 30, padding: 20, backgroundColor: '#000' }}><Text>qwe</Text></View>
</View>
</View>
</ScrollView>
</View>
</Animated.View>
</View>
);
};