web-dev-qa-db-fra.com

Faites glisser un ScrollView puis continuez le défilement dans React Native

Ce que je veux (GIF)

Voici un GIF (de qualité réduite) sur ce que je veux réaliser.

enter image description here

Ce que je veux (texte)

J'ai un scrollview, qui est positionné à la moitié de mon écran.

Ce que je veux, c'est faire glisser ce scrollview vers le haut, puis, quand il atteint une certaine position, envoyer le drag touch event à scrollview lui-même, afin qu'il puisse continuer le défilement.

Mes essais

  • Mettez le scrollview en plein écran au premier plan et ajoutez un demi-écran de remplissage à son contentContainerStyle. Cela a bien fonctionné, mais je n'ai pas pu cliquer sur la vue derrière. Existe-t-il un moyen de cliquer dans la zone vide d'une vue de défilement?
  • J'ai également essayé de détecter la position du défilement, afin de déplacer la vue vers le haut en conséquence

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

    mais n'a pas fonctionné lorsque je l'ai testé sur le simulateur iOS. L'événement n'est même pas déclenché. React Native Docs indique que onScroll a besoin de scrollEventThrottle pour fonctionner. Cependant, scrollEventThrottle n'est que disponible sur iOS . Et dans mon cas, je le veux sur Android aussi.
    .

Alors, pouvez-vous me donner quelques conseils pour y parvenir s'il vous plaît :)?

Merci,

24
David

J'ai essayé plusieurs options. C'est ma solution qui fonctionne le mieux en termes de performances. Bien sûr, ce n'est qu'un exemple de travail, vous devrez peut-être l'optimiser un peu plus pour répondre parfaitement à vos besoins.

Démo:

Demo Gif

Explication:

L'idée de base est de garder la carte tout le temps en arrière-plan de la superposition. La superposition est absolument positionnée et contient deux vues. Une vue est transparente, où nous pouvons toujours voir et contrôler la carte, l'autre vue contient le ScrollView réel. L'astuce consiste à définir pointerEvents="box-none" de la superposition parent et désactivez pointerEvents avec pointerEvents="none" de Afficher où nous voulons interagir avec la carte.

Méthode de rendu de base:

  <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>

Fonction de défilement:

Si nous faisons défiler le ScrollView, nous voulons réduire la vue vide, afin que le ScrollView devienne plein écran. Par conséquent, nous écoutons la méthode onScroll du ScrollView. Voir code et commentaires ci-dessous:

  _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});
      }
    }
  }

Avec scrollEventThrottle prop de ScrollView, nous pouvons contrôler la fréquence à laquelle _onScroll la méthode doit être appelée. (Ici, vous devrez probablement affiner)

Code complet et collation de travail

https://snack.expo.io/@tim1717/rnmapwithoverlay

7
Tim

Utilisez react-native-reeanimated-bottom-sheet pour y parvenir: https://github.com/osdnk/react-native-reanimated-bottom-sheet

0
jskidd3

Je pense qu'il vaut mieux placer à la fois MapView et BottomView dans un ScrollView.

Il enregistrera le comportement de défilement naturel et empêchera les effets secondaires comme les rayures blanches lors du défilement vers le bas ou la vue de dessus disparaissant lors du défilement vers le haut. Le problème principal ici est de savoir comment faire un effet "gel" pour le MapView.

Il est agréable d'utiliser l'effet de parallaxe en transformant MapView à l'intérieur de Animated conteneur relativement à un événement scroll. Je pense que bibliothèque animée avec composants animables sera une bonne solution pour des problèmes comme celui-ci:

   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>
    }

En fait, si vous ne voulez pas d'effet de parallaxe, vous pouvez remplacer Animated.multiply(this.scroll, 0.8) avec juste this.scroll

Vous pouvez voir un exemple complet ici: exemple de code

Capture d'écran

0
Denis Zakharov