3
votes

React Native Overflow Touchable ne fonctionne pas sous Android

Veuillez consulter mon Expo Snack .

Les éléments de liste déroulante sont accessibles sous iOS mais pas sous Android. La hauteur fixe du conteneur (boîte grise) cause ce problème, mais je dois garder la hauteur fixe pour ma barre d'outils.

J'ai essayé d'utiliser le package react-native-view-overflow mais pas de chance. Il nécessite un lien react-native , en attendant, je ne peux pas éjecter mon projet car j'utilise des packages Expo qui seront cassés si j'éjecte.

Avez-vous des suggestions pour rendre les éléments du menu déroulant accessibles sous Android?

 entrez la description de l'image ici


0 commentaires

3 Réponses :


0
votes

J'ai changé votre code, vérifiez ceci: Lien Snack

Cela résout votre problème, mais vous pouvez mettre à jour votre version native de réaction pour inclure ce commit qui ajoute la prise en charge de la propriété de style overflow sur React Native pour Android.


1 commentaires

Vous créez un conteneur externe dont la hauteur est dynamique. J'ai besoin d'une hauteur fixe pour créer une barre d'outils. Une barre d'outils ne doit pousser aucun contenu en dessous.



0
votes

Je n'utiliserais pas de dépendance à la place, je la gérerais moi-même.

  1. Créez un composant appelé DropDown qui couvre tout l'écran avec une position absolue (afin qu'il n'affecte pas la position des autres éléments sur l'écran). Ce composant est invisible lorsqu'il est inactif.
  2. Lorsque le bouton est enfoncé, sa position est mesurée dans la vue et elle est ensuite transmise au composant DropDown .
  3. Avec ses accessoires mis à jour, le composant DropDown est de nouveau rendu et un petit menu s'affiche à proximité du bouton d'origine qui a été enfoncé.
  4. En appuyant sur un élément du menu, vous rappelez le composant principal et changez la visibilité du DropDown pour le rendre invisible.
  5. Le fait d'appuyer sur l'arrière-plan rappelle également le composant principal et change la visibilité du DropDown pour le rendre invisible.

Voici le code, mais je l'ai également mis dans une collation pour que vous puissiez jouer avec https://snack.expo.io/@andypandy/dropdownmenu

Il y a beaucoup de possibilités que vous pouvez faire avec cela. Vous pouvez passer des enfants comme accessoires, vous pouvez le connecter à redux et le définir à la racine de votre application afin qu'il puisse être utilisé n'importe où. Les styles peuvent être facilement modifiés. Il est vraiment assez flexible dans ce que vous pouvez en faire. Je l'ai utilisé dans de nombreuses applications qui sont actuellement en ligne dans les deux magasins d'applications.

App.js

import React from 'react';
import { 
  Text, 
  View, 
  StyleSheet,
  TouchableOpacity
} from 'react-native';

export default class App extends React.Component {

  render() {
    return (
      <TouchableOpacity onPress={this.props.onPress}>
        <View style={styles.button}>
          <Text style={{color: 'white'}}>{this.props.title}</Text>
        </View>
      </TouchableOpacity>
    )
  }
}

const styles = StyleSheet.create({
  button: {
    backgroundColor: '#336699', 
    padding: 10, 
    borderRadius: 5
  }
});

DropDown.js

import React from 'react';
import { Text, View, StyleSheet, TouchableWithoutFeedback, TouchableOpacity} from 'react-native';

export default class DropDown extends React.Component {

  render() {

    if (this.props.show) {
      const { y: top, x: left } = this.props.position;
      const width = 100;
      return (
        <TouchableWithoutFeedback onPress={() => this.props.hide('background pressed')}>
          <View style={styles.container}>
              <View style={[styles.menu, { top, left: left - width/2, width}]}>

              <TouchableOpacity style={{width, alignItems: 'center', paddingTop: 5}} onPress={() => this.props.hide('Item 1')}>
                <Text>Item 1</Text>
              </TouchableOpacity>

              <TouchableOpacity style={{width, alignItems: 'center', paddingTop: 5}} onPress={() => this.props.hide('Item 2')}>
                <Text>Item 2</Text>
              </TouchableOpacity>

              <TouchableOpacity style={{width, alignItems: 'center', paddingTop: 5}} onPress={() => this.props.hide('Item 3')}>
                <Text>Item 3</Text>
              </TouchableOpacity>

              <TouchableOpacity style={{width, alignItems: 'center', paddingVertical: 5}} onPress={() => this.props.hide('Item 4')}>
                <Text>Item 4</Text>
              </TouchableOpacity>
              </View>
          </View>
        </TouchableWithoutFeedback>
      );
    } else {
      return null
    }
  }
}

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0
  },
  menu: {
    position: 'absolute',
    backgroundColor: 'white',
    alignItems: 'center',
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 5,
    },
    shadowOpacity: 0.36,
    shadowRadius: 6.68,
    elevation: 11,
  }
});

MyButton.js

import React from 'react';
import { 
  Text, 
  View, 
  StyleSheet,
  UIManager,
  findNodeHandle,
  TouchableOpacity
} from 'react-native';
// import components
import DropDown from './DropDown';
import MyButton from './MyButton';

export default class App extends React.Component {

  state = {
    show: false,
    position: {}
  }

  // handle showing the dropdown
  showDropDown = () => {
    if (this.button) {
      // use the uimanager to measure the button's position in the window
      UIManager.measure(findNodeHandle(this.button), (x, y, width, height, pageX, pageY) => {
        const position = { left: pageX, top: pageY, width: width, height: height };
        // setState, which updates the props that are passed to the DropDown component
        this.setState({show: true, position: { x: pageX + (width / 2), y: pageY + (2 * height / 3) }})
      });
    }
  }

  // hide the dropdown
  hideDropDown = (item) => {
    alert(item)
    this.setState({show: false, position: {}})
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={{height: 100, width: 300, backgroundColor: 'yellow', alignItems: 'center', justifyContent: 'center'}}>
          <MyButton
            ref={ref => {this.button = ref}}
            onPress={this.showDropDown}
            title={'Menu'}
          />
        </View>
          {/* Anything to be rendered below the DropDown should appear before the DropDown. So for best performance all components should go here. */}
        <DropDown show={this.state.show} position={this.state.position} hide={this.hideDropDown}/>
          {/* If you place a component here, it will appear above the DropDown and may interfere with how the DropDown works. You should not put anything here. */}
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'white'
  }
});


8 commentaires

Il semble que lorsque j'appuie sur la liste déroulante, le composant parent se déplace / pousse vers le bas. Pousse-t-il un contenu sous le conteneur parent déroulant?


Il ne doit pousser aucun contenu car le composant DropDown est absolument positionné au-dessus de tous les composants. Le composant DropDown doit être le dernier composant ajouté à la vue afin que tous les composants soient en dessous.


Considérez le composant DropDown comme une superposition sur votre écran. Cela signifie également que, comme il s'agit d'une superposition, tout ce qui y est rendu n'affectera pas la position de quoi que ce soit en dessous. J'utilise généralement DropDown avec redux et je mets le menu DropDown à la racine de mon application pour que tout soit terminé. Cela dépend vraiment de la façon dont vous l'utilisez. Placez le composant DropDown au mauvais endroit et il ne fonctionnera pas comme prévu. Il doit s'agir de la dernière vue rendue. Si vous regardez mon App.js , vous verrez que c'est la dernière vue rendue.


Donc, si mon contenu ci-dessous est rendu à la demande, la barre d'outils doit également être rendue pour être le dernier rendu?


La valeur de retour par défaut de DropDown est null donc il ne rendra pas quelque chose à moins que vous ne le lui disiez. Il vous suffit de l'avoir comme dernier élément de la vue. Comme je l'ai fait dans App.js . Si vous voulez voir plus clairement comment cela fonctionne, ajoutez un backgroundColor au conteneur dans le DropDown.js cela couvrira tout l'écran lorsque le DropDown sera affiché. Ensuite, dans App.js , ajoutez quelque chose après le composant DropDown. Vous devriez voir qu'il apparaîtra au-dessus du composant DropDown. L'ordre dans lequel vous spécifiez les composants dans App.js est important. J'ai ajouté quelques commentaires à mon App.js


@JeafGilbert Comment ça va?


Désolé, Andrew ne l'a pas encore appliqué, je vais l'essayer ce soir.


@JeafGilbert comment ça s'est passé?



0
votes

Il semble que lorsque la liste déroulante se développe, elle s'écoule hors de la vue car vous avez donné une hauteur fixe.

Donc, pour contourner le problème, vous pouvez utiliser la propriété minHeight au lieu de height .

cela garantira qu'au moins vous obtenez votre taille minimale et si nécessaire, il peut utiliser plus de hauteur, comme lorsque vous développez la liste déroulante.

la correction est donnée ci-dessous,

dropdownContainer: {
    width:340,
    minHeight:115,// changed this from height:115
    ...
    ...
  },


1 commentaires

Je dois avoir une hauteur fixe, une barre d’outils ne doit pas pousser de contenu en dessous.