web-dev-qa-db-ja.com

ScrollViewを上にドラッグしてから、スクロールを続けますReact Native

欲しいもの(GIF)

これは、私が達成したいことについて(品質が低下した)GIFです。

enter image description here

欲しいもの(テキスト)

画面の半分に配置されているscrollviewがあります。

そのscrollviewを上にドラッグし、特定の位置に到達したら、drag touch eventscrollview自体に送信して、スクロールを続行できるようにします。

私の試み

  • スクロールビューをフルスクリーンでフォアグラウンドに配置し、そのcontentContainerStyleに半画面のパディングトップを追加します。うまくいきましたが、背後のビューをクリックできませんでした。スクロールビューの空の領域をクリックする方法はありますか?
  • それに応じてビューを上に移動するために、スクロール位置も検出しようとしました

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

    iOSシミュレーターでテストしたところ機能しませんでした。イベントは発生しません。 React Native Docs は、onScrollが機能するためにscrollEventThrottleが必要であることを示しています。ただし、scrollEventThrottleiOSで利用可能 のみです。そして私の場合、私はAndroidでもそれを望んでいます。
    これが正常に達成された場合、別のUI問題に直面するはずです。ScrollViewを上にドラッグすると、ビューがまだ希望の位置にないときにスクロールできないようにするにはどうすればよいですか?

それで、これを達成するためのヒントを教えてください:)?

ありがとうございました、

24
David

私はいくつかのオプションを試しました。これは、パフォーマンス面で最適に機能する私のソリューションです。もちろん、これは実際の例にすぎません。ニーズに完全に一致させるには、さらに最適化する必要がある場合があります。

デモ:

Demo Gif

説明:

基本的な考え方は、オーバーレイの背景に常にマップを保持することです。オーバーレイは絶対的に配置され、2つのビューを含みます。 1つのビューは透明で、マップを表示および制御できます。もう1つのビューには実際のScrollViewが含まれています。トリックは、親オーバーレイのpointerEvents="box-none"を設定し、マップと対話するビューのpointerEvents="none"でpointerEventsを無効にすることです。

基本的なレンダリング方法:

  <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を下にスクロールする場合、空のビューを縮小して、ScrollViewがフルスクリーンになるようにします。したがって、ScrollViewのonScrollメソッドをリッスンします。以下のコードとコメントを参照してください。

  _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

7
Tim

これを達成するには、react-native-reanimated-bottom-sheetを使用します。 https://github.com/osdnk/react-native-reanimated-bottom-sheet

0
jskidd3

MapViewとBottomViewの両方を1つの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_に置き換えることができます

ここで完全な例を見ることができます: コード例

画面キャプチャ

0
Denis Zakharov