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>
);
}
}
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
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)
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 :)
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.