Перетащите ScrollView, затем продолжите прокрутку в React Native.
Что я хочу (GIF)
Вот (GIF с пониженным качеством) о том, чего я хочу достичь.
Что я хочу (Текст)
У меня есть scrollview
, который расположен на половине моего экрана.
Я хочу перетащить этот scrollview
вверх, а затем, когда он достигнет определенной позиции, отправить сам drag touch event
в scrollview
, чтобы он мог продолжать прокрутку.
Мои попытки
- Поместите вид прокрутки в полноэкранный режим на переднем плане и добавьте верхнюю часть экрана на половину экрана к
contentContainerStyle
. Это работало хорошо, но я не мог щелкнуть по представлению позади него. Есть ли способ щелкнуть по пустой области прокрутки?
Я также попытался определить положение прокрутки, чтобы переместить вид вверх соответственно.
<ScrollView onScroll={event => moveScrollViewUpIfNeeded(event)}>
...
</ScrollView>
но не сработало, когда я тестировал его на симуляторе iOS. Событие даже не состоялось. React Native Docs утверждает, что onScroll
нуждается в scrollEventThrottle
для работы. Тем не менее, scrollEventThrottle
доступен только на iOS. И в моем случае, я хочу это и на Android.
И если я успешно достигну этого, я столкнусь с еще одной проблемой пользовательского интерфейса: когда я перетаскиваю ScrollView вверх, как я могу предотвратить его прокрутку, когда представление еще не находится в требуемом положении?
Итак, можете ли вы дать мне несколько советов для достижения этого, пожалуйста :)?
Спасибо,
Ответы
Ответ 1
Я перепробовал несколько вариантов. Это мое решение, которое работает лучше всего с точки зрения производительности. Конечно, это всего лишь рабочий пример, вам может потребоваться еще немного его оптимизировать, чтобы он идеально соответствовал вашим потребностям.
Демонстрация:
Объяснение:
Основная идея состоит в том, чтобы постоянно держать карту на фоне наложения. Наложение абсолютно позиционировано и содержит два вида. Один вид прозрачен, где мы все еще можем видеть и контролировать карту, другой вид содержит фактический вид ScrollView. Хитрость заключается в том, чтобы установить pointerEvents="box-none"
родительского оверлея и отключить pointerEvents с pointerEvents="none"
из View, где мы хотим взаимодействовать с картой.
Основной метод рендеринга:
<SafeAreaView style={{flex: 1}}>
<MapView
initialRegion={region}
style={{height: HEIGHT, width: WIDTH}}
/>
<View pointerEvents="box-none"style={{height: HEIGHT, width: WIDTH, position: 'absolute'}}>
<View pointerEvents="none" style={{height: this.state.height, backgroundColor: 'transparent'}} />
<View style={{ height: HEIGHT-this.state.height, backgroundColor: 'white'}}>
<ScrollView onScroll={(e) => this._onScroll(e)} scrollEventThrottle={10} >
-- content of scrollview goes here ---
</ScrollView>
</View>
</View>
</SafeAreaView>
Функция прокрутки:
Если мы прокручиваем ScrollView вниз, мы хотим уменьшить пустой View, чтобы ScrollView стал полноэкранным. Поэтому мы слушаем метод onScroll
ScrollView. Смотрите код и комментарии ниже:
_onScroll(e){
// from the nativeEvent we can get the contentOffsett
var offset_y = e.nativeEvent.contentOffset.y;
if (offset_y > 0 ) {
if (this.state.height>=0){
// we are scrolling down the list, decrease height of the empty view
this.setState({height: this.state.height-offset_y});
}
}
if (offset_y <0){
if (this.state.height <= this.state.mapHeight){
// we are scrolling up the list, increase size of empty view/map view
this.setState({height: this.state.height-offset_y});
}
}
}
С помощью ScrollView scrollEventThrottle
мы можем контролировать, как часто следует вызывать метод _onScroll
. (Здесь вы, вероятно, должны настроить)
Полный код & Рабочая закуска
https://snack.expo.io/@tim1717/rnmapwithoverlay
Ответ 2
Я думаю, что лучше поместить MapView и BottomView в один ScrollView
.
Это сохранит естественное поведение прокрутки и предотвратит побочные эффекты, такие как белые полосы при прокрутке вниз или исчезновение вида сверху при прокрутке вверх. Основная проблема заключается в том, как сделать эффект "заморозки" для MapView
.
Полезно использовать эффект параллакса путем преобразования MapView
внутри контейнера Animated
относительно события прокрутки. Я думаю, анимированная библиотека с анимируемыми компонентами будет хорошим решением для таких проблем:
scroll = new Animated.Value(0)
render() {
return <Animated.ScrollView ...
onScroll={Animated.event([{nativeEvent: {contentOffset: {y: this.scroll}}}], {useNativeDriver: true})}>
<Animated.View
style={
{ ...transform:
[{translateY: Animated.multiply(this.scroll, 0.8)}]}}>
<MapView />
</Animated.View>
<BottomView />
</Animated.ScrollView>
}
На самом деле, если вам не нужен эффект параллакса, вы можете заменить Animated.multiply(this.scroll, 0.8)
просто this.scroll
Вы можете увидеть полный пример здесь: Пример кода
Скриншот