40

我在 KeyboardAvoidingView 中有一个 FlatList。显示键盘时,我想滚动到 FlatList 的末尾。

我正在监听确实被触发的“keyboardDidShow”事件,但它可能被触发得太早,因为在调用 scrollToEnd 后 FlatList 没有滚动到末尾。

我已经查看了 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>
    );
  }
}
4

5 回答 5

82

我正在制作一个聊天组件,我想要同样的东西。是这样的吗:

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

键盘弹出触发布局,所以这是固定的。到达的新聊天消息会触发内容更改,因此它也会滚动到底部(这是我想要的聊天窗口)

于 2018-01-01T14:03:14.253 回答
43

实际上,如果您总是想滚动到最后,意味着您总是想看到最新消息,对吗?

然后使用新版本的 react-native。并添加倒置以改变平面列表的倒置。

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

然后重新排列你的this.state.messages颠倒。那么您的最新消息将始终显示在平面列表的底部

就我而言,我不需要使用KeyboardAvoidingView

于 2017-11-01T13:02:07.103 回答
3

一些用户(@Nathileo)要求使用基于钩子的方法来滚动到 FlatList 的末尾。

  1. 首先,你需要实现 React 的 useRef 钩子:

    import {useRef} from 'react';

    const yourRef = useRef(null);

  2. 其次,FlatList 标签必须配备引用和所需的功能:

    <FlatList
      ref={yourRef}
      onContentSizeChange={() => yourRef.current.scrollToEnd() }
      onLayout={() => yourRef.current.scrollToEnd() }
    />
    
于 2021-02-09T20:51:10.457 回答
1

我一直在使用我制作的这个小组件来使用键盘管理平面列表高度。这使用了 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>
);

在这里我有这个教程,如果你更直观,我会展示它的作用:)

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

于 2018-04-25T13:09:51.363 回答
0

如上述评论所述,getItemLayout应该可以解决您的问题。

根据Reactive FlatList 文档

getItemLayout是一种可选优化,如果您先验地知道项目的高度,我们可以跳过动态内容的测量。getItemLayout是最有效的,并且如果您有固定高度的项目,则易于使用,例如:

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

如果您使用ItemSeparatorComponent,请不要忘记在计算结果偏移量时合并分隔符的高度或宽度。

于 2017-06-02T19:45:57.063 回答