Перетащите ScrollView, затем продолжите прокрутку в React Native.

Что я хочу (GIF)

Вот (GIF с пониженным качеством) о том, чего я хочу достичь.

enter image description here

Что я хочу (Текст)

У меня есть scrollview, который расположен на половине моего экрана.

Я хочу перетащить этот scrollview вверх, а затем, когда он достигнет определенной позиции, отправить сам drag touch event в scrollview, чтобы он мог продолжать прокрутку.

Мои попытки

  • Поместите вид прокрутки в полноэкранный режим на переднем плане и добавьте верхнюю часть экрана на половину экрана к contentContainerStyle. Это работало хорошо, но я не мог щелкнуть по представлению позади него. Есть ли способ щелкнуть по пустой области прокрутки?
  • Я также попытался определить положение прокрутки, чтобы переместить вид вверх соответственно.

    <ScrollView onScroll={event => moveScrollViewUpIfNeeded(event)}>
        ...
    </ScrollView>
    

    но не сработало, когда я тестировал его на симуляторе iOS. Событие даже не состоялось. React Native Docs утверждает, что onScroll нуждается в scrollEventThrottle для работы. Тем не менее, scrollEventThrottle доступен только на iOS. И в моем случае, я хочу это и на Android.
    И если я успешно достигну этого, я столкнусь с еще одной проблемой пользовательского интерфейса: когда я перетаскиваю ScrollView вверх, как я могу предотвратить его прокрутку, когда представление еще не находится в требуемом положении?

Итак, можете ли вы дать мне несколько советов для достижения этого, пожалуйста :)?

Спасибо,

Ответы

Ответ 1

Я перепробовал несколько вариантов. Это мое решение, которое работает лучше всего с точки зрения производительности. Конечно, это всего лишь рабочий пример, вам может потребоваться еще немного его оптимизировать, чтобы он идеально соответствовал вашим потребностям.

Демонстрация:

Demo Gif

Объяснение:

Основная идея состоит в том, чтобы постоянно держать карту на фоне наложения. Наложение абсолютно позиционировано и содержит два вида. Один вид прозрачен, где мы все еще можем видеть и контролировать карту, другой вид содержит фактический вид 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

Вы можете увидеть полный пример здесь: Пример кода

Скриншот