显示键盘后滚动到 FlatList 的末尾
Scroll to end of FlatList after displaying the keyboard
我在 KeyboardAvoidingView 中有一个 FlatList。当显示键盘时,我想滚动到 FlatList 的末尾。
我正在监听确实被触发的 'keyboardDidShow' 事件,但它可能被触发得太早,因为 FlatList 在调用 scrollToEnd 后没有滚动到末尾。
我研究了 KeyboardAvoidingView 的 onLayout 事件,但是仅仅设置 onLayout 事件来触发一个函数似乎阻止了 KeyboardAvoidingView 在显示键盘时调整它的大小。
<KeyboardAvoidingView behavior='padding' style={{ flex: 1}} onLayout={this._scrollEnd}>
代码:
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>
);
}
}
如上 所述,getItemLayout
应该可以解决您的问题。
根据Reactive FlatList documentation:
getItemLayout
is an optional optimizations that let us skip measurement of dynamic content if you know the height of items a priori. getItemLayout
is the most efficient, and is easy to use if you have fixed height items, for example:
getItemLayout={(data, index) => (
{length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
)}
如果您使用 ItemSeparatorComponent
,请不要忘记在计算结果偏移量时包含分隔符高度或宽度。
实际上如果你总是想滚动到最后,意味着你总是想看到最新的消息,对吗?
然后使用新版本的 react-native。并添加 inverted 来改变平面列表的颠倒。
<FlatList
inverted
style={{ flex:1}}
ref="flatList1"
data={this.state.messages}
renderItem={({ item }) => <Text>{item.text}</Text>}
/>
然后重新排列您的 this.state.messages。那么您的最新消息将始终显示在 flatlist
的底部
对于我的情况,我不需要使用 KeyboardAvoidingView
我正在制作一个聊天组件,我想要同样的东西。是不是这样:
<FlatList
ref={ref => this.flatList = ref}
onContentSizeChange={() => this.flatList.scrollToEnd({animated: true})}
onLayout={() => this.flatList.scrollToEnd({animated: true})}
...
/>
弹出键盘会触发布局,已修复。新的聊天消息到达会触发内容更改,因此它也会滚动到底部(这正是我聊天想要的 window)
我一直在使用我制作的这个小组件来通过键盘管理平面列表高度。这使用了 renderProps 模式,所以你可以重用它:)
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;
这里我们监听键盘事件,endcoordinates 给你键盘高度。这样你就可以用它来制作平面列表高度。
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>
);
这里我有这个教程,如果你更直观的话,我会展示它的作用:)
一些用户 (@Nathileo) 要求使用基于挂钩的方法来滚动到 FlatList 的末尾。
首先,你需要实现React的useRef钩子:
import {useRef} from 'react';
const yourRef = useRef(null);
其次,FlatList标签必须带有引用和需要的功能:
<FlatList
ref={yourRef}
onContentSizeChange={() => yourRef.current.scrollToEnd() }
onLayout={() => yourRef.current.scrollToEnd() }
/>
我在 KeyboardAvoidingView 中有一个 FlatList。当显示键盘时,我想滚动到 FlatList 的末尾。
我正在监听确实被触发的 'keyboardDidShow' 事件,但它可能被触发得太早,因为 FlatList 在调用 scrollToEnd 后没有滚动到末尾。
我研究了 KeyboardAvoidingView 的 onLayout 事件,但是仅仅设置 onLayout 事件来触发一个函数似乎阻止了 KeyboardAvoidingView 在显示键盘时调整它的大小。
<KeyboardAvoidingView behavior='padding' style={{ flex: 1}} onLayout={this._scrollEnd}>
代码:
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>
);
}
}
如上 getItemLayout
应该可以解决您的问题。
根据Reactive FlatList documentation:
getItemLayout
is an optional optimizations that let us skip measurement of dynamic content if you know the height of items a priori.getItemLayout
is the most efficient, and is easy to use if you have fixed height items, for example:
getItemLayout={(data, index) => (
{length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
)}
如果您使用 ItemSeparatorComponent
,请不要忘记在计算结果偏移量时包含分隔符高度或宽度。
实际上如果你总是想滚动到最后,意味着你总是想看到最新的消息,对吗?
然后使用新版本的 react-native。并添加 inverted 来改变平面列表的颠倒。
<FlatList
inverted
style={{ flex:1}}
ref="flatList1"
data={this.state.messages}
renderItem={({ item }) => <Text>{item.text}</Text>}
/>
然后重新排列您的 this.state.messages。那么您的最新消息将始终显示在 flatlist
的底部对于我的情况,我不需要使用 KeyboardAvoidingView
我正在制作一个聊天组件,我想要同样的东西。是不是这样:
<FlatList
ref={ref => this.flatList = ref}
onContentSizeChange={() => this.flatList.scrollToEnd({animated: true})}
onLayout={() => this.flatList.scrollToEnd({animated: true})}
...
/>
弹出键盘会触发布局,已修复。新的聊天消息到达会触发内容更改,因此它也会滚动到底部(这正是我聊天想要的 window)
我一直在使用我制作的这个小组件来通过键盘管理平面列表高度。这使用了 renderProps 模式,所以你可以重用它:)
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;
这里我们监听键盘事件,endcoordinates 给你键盘高度。这样你就可以用它来制作平面列表高度。
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>
);
这里我有这个教程,如果你更直观的话,我会展示它的作用:)
一些用户 (@Nathileo) 要求使用基于挂钩的方法来滚动到 FlatList 的末尾。
首先,你需要实现React的useRef钩子:
import {useRef} from 'react';
const yourRef = useRef(null);
其次,FlatList标签必须带有引用和需要的功能:
<FlatList ref={yourRef} onContentSizeChange={() => yourRef.current.scrollToEnd() } onLayout={() => yourRef.current.scrollToEnd() } />