web-dev-qa-db-fra.com

Faites défiler jusqu'à la fin de FlatList après avoir affiché le clavier

J'ai une FlatList à l'intérieur d'un KeyboardAvoidingView. Lorsque le clavier est affiché, j'aimerais faire défiler l'écran jusqu'à la fin de la liste à plat. 

J'écoute l'événement 'keyboardDidShow' qui est déclenché, mais il se peut qu'il soit déclenché trop tôt, car FlatList n'est pas défilé jusqu'à la fin après l'appel de scrollToEnd.

J'ai examiné l'événement onLayout de KeyboardAvoidingView; toutefois, le fait de définir l'événement onLayout pour déclencher une fonction semble empêcher le KeyboardAvoidingView de régler sa taille lorsque le clavier est affiché.

<KeyboardAvoidingView behavior='padding' style={{ flex: 1}} onLayout={this._scrollEnd}>

Code:

import React from 'react';
import {Image, Linking, Platform, ScrollView, StyleSheet, Text, TouchableOpacity, View, Button, Alert, FlatList, TextInput, KeyboardAvoidingView, Keyboard} from 'react-native';
import { MonoText } from '../components/StyledText';

export default class HomeScreen extends React.Component {
  constructor() {
    super();
    this.state = {
      messages: getMessages()
    };

    this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._scrollEnd);
    this.keyboardDidShowListener = Keyboard.addListener('keyboardDidHide', this._scrollEnd);
  }

  _scrollEnd = (evt) => {
    this.refs.flatList1.scrollToEnd();
  }

  render() {
    return (
      <KeyboardAvoidingView behavior='padding' style={{ flex: 1}} >
        <FlatList
          style={{ flex:1}}
          ref="flatList1"
          data={this.state.messages}
          renderItem={({ item }) => <Text>{item.text}</Text>}
        />
      </KeyboardAvoidingView>
    );
  }
}
18
user1855085

en fait, si vous voulez toujours faire défiler l'écran jusqu'à la fin, vous voulez toujours voir le dernier message, est-ce que j'ai raison?

utilisez ensuite la nouvelle version de react-native. et ajoutez inversé pour changer la liste à l'envers. 

<FlatList
      inverted
      style={{ flex:1}}
      ref="flatList1"
      data={this.state.messages}
      renderItem={({ item }) => <Text>{item.text}</Text>}
    />

puis réorganisez votre this.state.messages à l’envers. alors votre dernier message sera toujours affiché au bas de la liste à plat

Pour mon cas, je n'ai pas besoin d'utiliser KeyboardAvoidingView

14
Kyo Kurosagi

Je crée un composant de chat et je veux les mêmes choses. Est-ce que ça a plu comme ça:

<FlatList
   ref={ref => this.flatList = ref}
   onContentSizeChange={() => this.flatList.scrollToEnd({animated: true})}
   onLayout={() => this.flatList.scrollToEnd({animated: true})}
   ...
/>

Un clavier surgissant déclenche une mise en page, donc c'est corrigé. Les nouveaux messages de discussion qui arrivent déclenchent des modifications de contenu, de sorte qu'ils défilent également vers le bas (ce que je voulais pour ma fenêtre de discussion)

20
Anthony De Smet

J'utilise ce petit composant que j'ai créé pour gérer la hauteur de la liste d'affichage avec le clavier. Ceci utilise le modèle renderProps afin que vous puissiez le réutiliser :)

import { PureComponent } from 'react';
import { Keyboard, Dimensions, Animated } from 'react-native';

const DURATION = 200;

class ListSpacer extends PureComponent {
  state = {
    screenHeight: Dimensions.get('window').height,
    flatListHeight: new Animated.Value(Dimensions.get('window').height),
  };

  componentDidMount() {
    this._keyboardDidShowListener = Keyboard.addListener(
      'keyboardDidShow',
      this._keyBoardDidShow,
    );
    this._keyboardDidHideListener = Keyboard.addListener(
      'keyboardDidHide',
      this._keyBoardDidHide,
    );
  }

  componentWillUnmount() {
    this._keyboardDidShowListener.remove();
    this._keyboardDidHideListener.remove();
  }

  _keyBoardDidShow = e => {
    Animated.timing(this.state.flatListHeight, {
      toValue: Dimensions.get('window').height - e.endCoordinates.height,
      duration: DURATION,
    }).start();
  };

  _keyBoardDidHide = () => {
    Animated.timing(this.state.flatListHeight, {
      toValue: Dimensions.get('window').height,
      duration: DURATION,
    }).start();
  };

  render() {
    const renderProps = {
      flatListHeight: this.state.flatListHeight,
    };

    if (this.props.children) {
      return this.props.children(renderProps);
    }

    return this.props.render(renderProps);
  }
}

export default ListSpacer;

Ici, nous écoutons les événements de clavier, et les coordonnées géographiques vous donnent la hauteur du clavier. De cette façon, vous pouvez faire la hauteur de la flatlist avec elle.

import {
  FlatList,
  KeyboardAvoidingView,
  Animated,
} from 'react-native';

const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);

return (
  <ListSpacer>
    {({ flatListHeight }) => (
      <KeyboardAvoidingView
        behavior="padding"
        keyboardVerticalOffset={INPUT_HEIGHT}
      >
        <AnimatedFlatList
          inverted
          style={{ height: flatListHeight }}
          data={data.comments}
          keyExtractor={this._keyExtractor}
          renderItem={this._renderItem}
          contentContainerStyle={styles.contentList}
        />
      </KeyboardAvoidingView>
    )}
  </ListSpacer>
);

Ici, j'ai ces tutoriels où je montre ce que cela fait si vous êtes plus visuel :)

https://youtu.be/2QnPZXCIN44?t=28m43s

0
EQuimper

Comme indiqué ci-dessus commentaire , getItemLayout devrait résoudre votre problème.

Selon documentation Reactive FlatList :

getItemLayout est une optimisation facultative nous permettant d’ignorer la mesure du contenu dynamique si vous connaissez la hauteur des éléments a priori. getItemLayout est le plus efficace et il est facile à utiliser si vous avez des objets à hauteur fixe, par exemple:

getItemLayout={(data, index) => (
  {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
)}

Si vous utilisez ItemSeparatorComponent, n'oubliez pas d'intégrer la hauteur ou la largeur du séparateur lors du calcul du décalage résultant.

0
lax1089