【问题标题】:Scroll to end of FlatList after displaying the keyboard显示键盘后滚动到 FlatList 的末尾
【发布时间】:2017-10-16 06:35:47
【问题描述】:

我在 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>
    );
  }
}

【问题讨论】:

  • 您是否尝试添加getItemLayout 属性?看起来它修复了它:facebook.github.io/react-native/releases/0.44/docs/…。或者你的物品高度不是静态的?
  • 你在哪个平台?赢,操作系统,林?
  • 这段代码在我的电脑上运行。您能否更详细地说明发生了什么?卷轴永远不会发生?还是内容被剪掉了?
  • 您发布的内容对我来说就像是一种魅力。感觉你不应该在构造函数中添加监听器,而是在 componentWillMount 中,然后在 componentWillUnmount 中再次删除它们。

标签: react-native react-native-flatlist


【解决方案1】:

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

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

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

【讨论】:

  • 老兄的回答太棒了!
  • Anthony,你能告诉我你是如何实现这个“键盘弹出触发布局,所以这是固定的。”
  • 当键盘弹出时,屏幕必须重新渲染以调整其大小。这意味着 FlatList 也将获得新的尺寸(高度)并且将触发布局事件。发生这种情况时,我们滚动到列表的末尾: onLayout={() => this.flatList.scrollToEnd({animated: true})}
  • 感谢 onLayout!我不知道 :) 当我更改键盘显示事件的高度并更改 FlatlList 包装器高度时,onLayout 做了一个技巧:)
  • 谢谢,效果很好。我建议同时使用 initialNumToRender={1}。如果列表中有大量数据,则列表最初会加载所有内容,然后移回顶部并再次向下动画。例如,如果您将 intialNum 设置为 1,它会防止 intial stutter/jump。
【解决方案2】:

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

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

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

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

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

【讨论】:

  • 好主意,inverted 正是我要找的东西
  • 伙计,这也是我需要的,?
  • 谢谢,这对我也有用。但是要小心:它也会反转内容,因此您需要以其他方式对其进行排序
【解决方案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() }
    />
    

【讨论】:

    【解决方案4】:

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

    这里我们监听键盘事件,结束坐标为您提供键盘高度。这样你就可以用它来制作平面列表的高度。

    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

    【讨论】:

      【解决方案5】:

      如上所述commentgetItemLayout 应该可以解决您的问题。

      根据Reactive FlatList documentation

      getItemLayout 是一个可选优化,如果您先验地知道项目的高度,我们可以跳过动态内容的测量。 getItemLayout 是最高效的,如果你有固定高度的物品,它很容易使用,例如:

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

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

      【讨论】:

      • 当您确切知道ITEM_HEIGHT时,此解决方案才有效,动态项目高度如何?
      猜你喜欢
      • 2019-03-28
      • 2016-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多