Comment faire pour faire glisser automatiquement la fenêtre derrière le clavier quand TextInput a la mise au point?

j'ai vu ce hack pour les applications natives pour faire défiler automatiquement la fenêtre, mais se demandant la meilleure façon de le faire pour react-native... Quand un champ se focalise et est positionné bas dans la vue, le clavier couvre le champ de texte. Vous pouvez voir ce problème dans L'exemple TextInputExample D'UIExplorer.js vue. Quelqu'un a une bonne solution?

87
demandé sur McG 2015-03-28 06:12:49

14 réponses

2017 Réponse

le KeyboardAvoidingView est probablement la meilleure façon d'y aller maintenant. Consultez les docs ici . C'est vraiment simple comparé au module Keyboard qui donne plus de contrôle au développeur pour effectuer des animations. Spencer Carli a démontré tous les moyens possibles sur son blog moyen .

2015 Répondre

la bonne façon de le faire dans react-native ne nécessite pas de bibliothèques externes, tire parti du code natif, et inclut des animations.

définissez D'abord une fonction qui gérera l'événement onFocus pour chaque TextInput (ou tout autre composant vers lequel vous voulez faire défiler):

// Scroll a component into view. Just pass the component ref string.
inputFocused (refName) {
  setTimeout(() => {
    let scrollResponder = this.refs.scrollView.getScrollResponder();
    scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
      React.findNodeHandle(this.refs[refName]),
      110, //additionalOffset
      true
    );
  }, 50);
}

puis, dans votre fonction de rendu:

render () {
  return (
    <ScrollView ref='scrollView'>
        <TextInput ref='username' 
                   onFocus={this.inputFocused.bind(this, 'username')}
    </ScrollView>
  )
}

utilise le RCTDeviceEventEmitter pour clavier les événements et le dimensionnement des mesures de la position du composant à l'aide de RCTUIManager.measureLayout , et calcule exactement de défilement mouvement nécessaire dans scrollResponderInputMeasureAndScrollToKeyboard .

vous pouvez vouloir jouer avec le paramètre additionalOffset , pour s'adapter aux besoins de votre conception D'interface utilisateur spécifique.

78
répondu Sherlock 2018-04-02 16:52:10

Facebook open sourcing KeyboardAvoidingView dans react native 0.29 pour résoudre ce problème. Exemple de Documentation et d'utilisation peut être trouvé ici .

26
répondu farwayer 2016-09-24 14:51:12

nous avons combiné une partie du code react-native-keyboard-spacer et le code de @Sherlock pour créer un composant KeyboardHandler qui peut être enroulé autour de n'importe quelle vue avec des éléments TextInput. Fonctionne comme un charme! :- )

/**
 * Handle resizing enclosed View and scrolling to input
 * Usage:
 *    <KeyboardHandler ref='kh' offset={50}>
 *      <View>
 *        ...
 *        <TextInput ref='username'
 *          onFocus={()=>this.refs.kh.inputFocused(this,'username')}/>
 *        ...
 *      </View>
 *    </KeyboardHandler>
 * 
 *  offset is optional and defaults to 34
 *  Any other specified props will be passed on to ScrollView
 */
'use strict';

var React=require('react-native');
var {
  ScrollView,
  View,
  DeviceEventEmitter,
}=React;


var myprops={ 
  offset:34,
}
var KeyboardHandler=React.createClass({
  propTypes:{
    offset: React.PropTypes.number,
  },
  getDefaultProps(){
    return myprops;
  },
  getInitialState(){
    DeviceEventEmitter.addListener('keyboardDidShow',(frames)=>{
      if (!frames.endCoordinates) return;
      this.setState({keyboardSpace: frames.endCoordinates.height});
    });
    DeviceEventEmitter.addListener('keyboardWillHide',(frames)=>{
      this.setState({keyboardSpace:0});
    });

    this.scrollviewProps={
      automaticallyAdjustContentInsets:true,
      scrollEventThrottle:200,
    };
    // pass on any props we don't own to ScrollView
    Object.keys(this.props).filter((n)=>{return n!='children'})
    .forEach((e)=>{if(!myprops[e])this.scrollviewProps[e]=this.props[e]});

    return {
      keyboardSpace:0,
    };
  },
  render(){
    return (
      <ScrollView ref='scrollView' {...this.scrollviewProps}>
        {this.props.children}
        <View style={{height:this.state.keyboardSpace}}></View>
      </ScrollView>
    );
  },
  inputFocused(_this,refName){
    setTimeout(()=>{
      let scrollResponder=this.refs.scrollView.getScrollResponder();
      scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
        React.findNodeHandle(_this.refs[refName]),
        this.props.offset, //additionalOffset
        true
      );
    }, 50);
  }
}) // KeyboardHandler

module.exports=KeyboardHandler;
12
répondu John kendall 2015-11-07 17:17:30

vous devez d'abord installer react-native-keyboardevents .

  1. Dans XCode, dans l'explorateur de projets, cliquez-droit sur les Bibliothèques ➜ Ajouter Fichiers à [nom de votre projet] aller à node_modules react-native-keyboardévents et ajouter le .xcodeproj fichier
  2. en XCode, dans le projet de navigation, sélectionnez votre projet. Ajouter la lib*.a partir de la keyboardevents projet vers les Phases de construction de votre projet Cliquer .XCODEPROJ fichier que vous avez ajouté avant dans le navigateur de projet et aller la construction Onglet paramètres. Assurez-vous que' All 'est activé (au lieu de'Basic'). Recherchez les chemins de recherche de L'en-tête et assurez-vous qu'il contient les deux $(SRCROOT)/../réagir indigènes/Réagir et $(SRCROOT)/../../Réagir marque les deux récursif.
  3. Exécuter votre projet (Cmd+R)

puis retour en JavaScript land:

vous devez importer le react-native-keyboardevents.

var KeyboardEvents = require('react-native-keyboardevents');
var KeyboardEventEmitter = KeyboardEvents.Emitter;

ensuite, dans votre vue, ajouter un État pour l'espace clavier et mettre à jour à partir de l'écoute des événements clavier.

  getInitialState: function() {
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, (frames) => {
      this.setState({keyboardSpace: frames.end.height});
    });
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, (frames) => {
      this.setState({keyboardSpace: 0});
    });

    return {
      keyboardSpace: 0,
    };
  },

enfin, ajoutez un espaceur à votre fonction de rendu sous tout ce qui augmente la taille, il fait monter vos affaires.

<View style={{height: this.state.keyboardSpace}}></View>

il est également possible d'utiliser l'api d'animation, mais pour des raisons de simplicité Nous ajustons juste après l'animation.

10
répondu brysgo 2015-04-17 17:29:24

réagissent-native-clavier-courant de défilement de la vue résolu le problème pour moi. réagissent-native-clavier-courant de défilement de la vue sur GitHub

7
répondu amirfl 2016-05-21 15:25:51

essayez ceci:

import React, {
  DeviceEventEmitter,
  Dimensions
} from 'react-native';

...

getInitialState: function() {
  return {
    visibleHeight: Dimensions.get('window').height
  }
},

...

componentDidMount: function() {
  let self = this;

  DeviceEventEmitter.addListener('keyboardWillShow', function(e: Event) {
    self.keyboardWillShow(e);
  });

  DeviceEventEmitter.addListener('keyboardWillHide', function(e: Event) {
      self.keyboardWillHide(e);
  });
}

...

keyboardWillShow (e) {
  let newSize = Dimensions.get('window').height - e.endCoordinates.height;
  this.setState({visibleHeight: newSize});
},

keyboardWillHide (e) {
  this.setState({visibleHeight: Dimensions.get('window').height});
},

...

render: function() {
  return (<View style={{height: this.state.visibleHeight}}>your view code here...</View>);
}

...

ça a marché pour moi. La vue rétrécit quand le clavier est affiché, et repousse quand il est caché.

6
répondu pomo 2016-03-05 09:22:47

je voulais juste mentionner, maintenant il y a un KeyboardAvoidingView dans RN. Il suffit de l'importer et de l'utiliser comme tout autre module dans RN.

Voici le lien pour l'engager sur la RN:

https://github.com/facebook/react-native/commit/8b78846a9501ef9c5ce9d1e18ee104bfae76af2e

il est disponible à partir de 0.29.0

ils ont également inclus un exemple sur UIExplorer.

4
répondu Aakash Sigdel 2016-07-25 06:21:11

peut-être est trop tard, mais la meilleure solution est d'utiliser une bibliothèque natif, IQKeyboardManager

il suffit de glisser-déposer IQKeyboardManager répertoire du projet de démonstration à votre projet iOS. C'est tout. Vous pouvez également configurer des valus, comme isToolbar activé, ou l'espace entre l'entrée de texte et le clavier dans L'AppDelegate.m de fichier. Plus de détails sur la personnalisation sont dans le lien de la page GitHub que j'ai ajouté.

4
répondu Adrian Zghibarta 2017-01-30 21:11:56

j'ai utilisé TextInput.onFocus et ScrollView.scrollTo.

...
<ScrollView ref="scrollView">
...
<TextInput onFocus={this.scrolldown}>
...
scrolldown: function(){
  this.refs.scrollView.scrollTo(width*2/3);
},
2
répondu shohey1226 2015-06-13 01:29:09

@Stephen

si cela ne vous dérange pas que la hauteur ne soit pas animée exactement au même rythme que le clavier apparaît, vous pouvez simplement utiliser LayoutAnimation, de sorte qu'au moins la hauteur ne saute pas à la place. par exemple

importez LayoutAnimation de react-native et ajoutez les méthodes suivantes à votre component.

getInitialState: function() {
    return {keyboardSpace: 0};
  },
   updateKeyboardSpace: function(frames) {
    LayoutAnimation.configureNext(animations.layout.spring);
    this.setState({keyboardSpace: frames.end.height});
  },

  resetKeyboardSpace: function() {
    LayoutAnimation.configureNext(animations.layout.spring);
    this.setState({keyboardSpace: 0});
  },

  componentDidMount: function() {
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  },

  componentWillUnmount: function() {
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  },

quelques exemples d'animations sont (j'utilise le printemps ci-dessus):

var animations = {
  layout: {
    spring: {
      duration: 400,
      create: {
        duration: 300,
        type: LayoutAnimation.Types.easeInEaseOut,
        property: LayoutAnimation.Properties.opacity,
      },
      update: {
        type: LayoutAnimation.Types.spring,
        springDamping: 400,
      },
    },
    easeInEaseOut: {
      duration: 400,
      create: {
        type: LayoutAnimation.Types.easeInEaseOut,
        property: LayoutAnimation.Properties.scaleXY,
      },
      update: {
        type: LayoutAnimation.Types.easeInEaseOut,
      },
    },
  },
};

mise à jour:

voir la réponse de @sherlock ci-dessous, comme pour react-native 0.11 le redimensionnement du clavier peut être résolu en utilisant la fonctionnalité intégrée.

2
répondu deanmcpherson 2015-09-21 01:38:05

Vous pouvez combiner quelques-unes des méthodes à quelque chose d'un peu plus simple.

Joindre un onFocus d'écoute sur vos entrées

<TextInput ref="password" secureTextEntry={true} 
           onFocus={this.scrolldown.bind(this,'password')}
/>

notre méthode de défilement vers le bas ressemble à quelque chose comme :

scrolldown(ref) {
    const self = this;
    this.refs[ref].measure((ox, oy, width, height, px, py) => {
        self.refs.scrollView.scrollTo({y: oy - 200});
    });
}

cela indique notre vue de défilement (n'oubliez pas d'ajouter un ref) pour faire défiler vers le bas à la position de notre entrée focalisée - 200 (c'est à peu près la taille du clavier)

componentWillMount() {
    this.keyboardDidHideListener = Keyboard.addListener(
      'keyboardWillHide', 
      this.keyboardDidHide.bind(this)
    )
}

componentWillUnmount() {
    this.keyboardDidHideListener.remove()
}

keyboardDidHide(e) {
    this.refs.scrollView.scrollTo({y: 0});
}

ici, nous réinitialisons notre faites défiler la vue en arrière vers le haut,

enter image description here

2
répondu Nath 2018-04-30 08:36:47

j'utilise une méthode plus simple, mais elle n'est pas encore animée. J'ai un État de composant appelé "bumpedUp" que j'ai par défaut à 0, mais défini à 1 Quand le textInput se focalise, comme ceci:

sur mon textInput:

onFocus={() => this.setState({bumpedUp: 1})}
onEndEditing={() => this.setState({bumpedUp: 0})}

j'ai aussi le style qui donne au conteneur d'emballage de tout sur cet écran une marge inférieure et une marge supérieure négative, comme ceci:

mythingscontainer: {
  flex: 1,
  justifyContent: "center",
  alignItems: "center",
  flexDirection: "column",
},
bumpedcontainer: {
  marginBottom: 210,
  marginTop: -210,
},

et puis sur le conteneur d'emballage, j'ai mis les styles comme ceci:

<View style={[styles.mythingscontainer, this.state.bumpedUp && styles.bumpedcontainer]}>

Ainsi, lorsque l'état" bumpedUp " est défini à 1, le style bumpedcontainer s'active et déplace le contenu vers le haut.

un Peu hacky et les marges sont codés en dur, mais il fonctionne :)

0
répondu Stirman 2015-06-22 21:48:43

j'utilise brysgo answer pour lever le bas de mon scrollview. Puis j'utilise l'onScroll pour mettre à jour la position actuelle du scrollview. J'ai alors trouvé ce React Native: obtenir la position d'un élément pour obtenir la position du textinput. Je puis faire quelques calculs simples à comprendre si l'entrée est dans la vue actuelle. Puis j'utilise scrollTo pour déplacer le montant minimum plus une marge. C'est assez lisse. Heres le code pour la partie défilante:

            focusOn: function(target) {
                return () => {
                    var handle = React.findNodeHandle(this.refs[target]);
                    UIManager.measureLayoutRelativeToParent( handle, 
                        (e) => {console.error(e)}, 
                        (x,y,w,h) => {
                            var offs = this.scrollPosition + 250;
                            var subHeaderHeight = (Sizes.width > 320) ? Sizes.height * 0.067 : Sizes.height * 0.077;
                            var headerHeight = Sizes.height / 9;
                            var largeSpace = (Sizes.height - (subHeaderHeight + headerHeight));
                            var shortSpace = largeSpace - this.keyboardOffset;
                            if(y+h >= this.scrollPosition + shortSpace) {
                                this.refs.sv.scrollTo(y+h - shortSpace + 20);
                            }
                            if(y < this.scrollPosition) this.refs.sv.scrollTo(this.scrollPosition - (this.scrollPosition-y) - 20 );
                        }
                     );
                };
            },
0
répondu aintnorest 2017-05-23 12:02:42

je réponds aussi à cette question. Enfin, je le résous en définissant la hauteur de chaque scène, telle que:

<Navigator ... sceneStyle={{height: **}} />

et, j'utilise aussi un module tiers https://github.com/jaysoo/react-native-extra-dimensions-android pour obtenir la vraie hauteur.

0
répondu Renguang Dong 2016-04-26 07:54:29