React Native - 当键盘弹出时调整ScrollView的位置 (iOS)

3
在我的聊天应用中,我遇到了一些问题,即当键盘从视图底部弹出时,无法动画滚动scrollview(聊天视图)以向上/调整。
如果您使用过任何主要的聊天应用程序,例如Messenger、WeChat、Line等,您会看到当键盘弹出时,您的聊天屏幕会平稳地上滑。目前,我已经模仿KeyboardAvoidingView并实现了类似的功能:
// Triggered by Keyboard.addListener("keyboardWillChangeFrame", onKeyboardChange);
  const onKeyboardChange = e => {
    if (!e) {
      //this is scroll view's contentInset.top
      setSpacing(0);
      return;
    }

    const { duration, easing, endCoordinates, startCoordinates } = e;
    let offset;
    if (startCoordinates) {
      offset = startCoordinates.screenY - endCoordinates.screenY;
    } else {
      offset = endCoordinates.height;
    }

    const spacing = offset > 0 ? offset : 0;
    if (duration && easing) {
      LayoutAnimation.configureNext({
        // We have to pass the duration equal to minimal accepted duration defined here: RCTLayoutAnimation.m
        duration: duration > 10 ? duration : 10,
        update: {
          duration: duration > 10 ? duration : 10,
          type: LayoutAnimation.Types[easing] || "keyboard"
        }
      });
    }
    //this is scroll view's contentInset.top
    setSpacing(spacing);
  };

正如您所看到的,我目前只是使用由KeyboardWillChangeFrame传递的事件来计算偏移量,并使用LayoutAnimation来动画滚动视图向上滑动。

它运行得相当不错,但我仍然能看到轻微的延迟。

在原生iOS开发中,可以通过使用animateKeyframes来实现:

@objc func keyboardWillShow(notification: NSNotification){
    let duration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double
    let curve = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! UInt
    let curFrame = (notification.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    let targetFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    let deltaY = targetFrame.origin.y - curFrame.origin.y

    UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIView.KeyframeAnimationOptions(rawValue: curve), animations: {
        self.view.frame.origin.y += deltaY
    })
}

但似乎在React Native中没有这个功能。 有没有办法使滚动视图尽可能平滑地调整为键盘从底部弹出?

1个回答

0

你需要做两件事情

1:首先使用react-native-keyboard-spacer使Textinput容器滚动

2:在键盘显示/隐藏时设置ChatList的偏移量

完整代码

import React from "react";
import { View, FlatList, Text, TextInput, Keyboard } from "react-native";
import KeyboardSpacer from "react-native-keyboard-spacer";

export default class App extends React.Component {
  state = {
    chat: [
      { id: 1, text: "Test1 1" },
      { id: 2, text: "Test1 2" },
      { id: 3, text: "Test1 3" },
      { id: 4, text: "Test1 4" },
      { id: 5, text: "Test1 5" },
      { id: 6, text: "Test1 6" },
      { id: 7, text: "Test1 7" },
      { id: 8, text: "Test1 8" },
      { id: 9, text: "Test1 9" },
      { id: 10, text: "Test1 10" },
      { id: 11, text: "Test1 11" },
      { id: 12, text: "Test1 12" },
      { id: 13, text: "Test1 13" },
      { id: 14, text: "Test1 14" },
      { id: 15, text: "Test1 15" },
      { id: 16, text: "Test1 16" },
      { id: 17, text: "Test1 17" },
      { id: 18, text: "Test1 18" },
      { id: 19, text: "Test1 19" },
      { id: 20, text: "Test1 20" },
      { id: 21, text: "Test1 21" },
      { id: 22, text: "Test1 22" },
      { id: 23, text: "Test1 23" },
      { id: 24, text: "Test1 24" }
    ]
  };

  scrollOffset = 0;
  keyboardHeight = 0;

  componentDidMount() {
    this.keyboardWillShowListener = Keyboard.addListener(
      "keyboardWillShow",
      this._keyboardWillShow
    );
    this.keyboardWillHideListener = Keyboard.addListener(
      "keyboardWillHide",
      this._keyboardWillHide
    );
  }

  componentWillUnmount() {
    this.keyboardWillShowListener.remove();
    this.keyboardWillHideListener.remove();
  }

  _keyboardWillShow = e => {
    this.keyboardHeight = e.endCoordinates
      ? e.endCoordinates.height
      : e.end.height;

    const newOffset = this.scrollOffset + this.keyboardHeight;
    this.chatList.scrollToOffset({ offset: newOffset, animated: true });
  };

  _keyboardWillHide = e => {
    const newOffset = this.scrollOffset - this.keyboardHeight;
    this.chatList.scrollToOffset({ offset: newOffset, animated: true });
  };

  handleScroll = e => {
    this.scrollOffset = e.nativeEvent.contentOffset.y;
  };

  render() {
    return (
      <View style={{ flex: 1, marginTop: 30 }}>
        <FlatList
          style={{ flex: 1 }}
          ref={ref => {
            this.chatList = ref;
          }}
          data={this.state.chat}
          renderItem={({ item }) => (
            <Text style={{ padding: 20 }}>{item.text}</Text>
          )}
          onScroll={this.handleScroll}
        />
        <TextInput
          placeholder="Enter Message"
          style={{ padding: 20, borderTopWidth: 1, borderColor: "black" }}
        />
        <KeyboardSpacer />
      </View>
    );
  }
}

应用程序预览

enter image description here


@Hikaru Watanabe,更新答案,添加样例代码。请在类似于WhatsApp、Messenger的应用中检查,移动的是底部的文本输入视图,而不是聊天列表。聊天列表将保持相同的偏移量。 - Mehran Khan
@Hikaru Watanabe。我也在谈论聊天界面。请再次检查Whatsapp。我添加了我制作的Whatsapp应用程序演示。请查看https://gph.is/g/ZnxYRkJ。当您要输入并打开键盘时,聊天列表将保持原位置。如果你添加了新消息,聊天列表将移到底部。 - Mehran Khan
https://gph.is/g/ZnxYRkJ 恰好是我想要实现的。在 https://gph.is/g/ZnxYRkJ 中,滚动视图偏移似乎随着键盘的出现而移动。但是在您的 AppPreview 中,flatlist/scrollview 看起来没有进行调整,这也是当我使用您建议的开源代码时发生的情况。 - Bubu
在您的应用程序预览中,TextInput 会随着键盘弹出而出现,但 ScrollView 的 contentView 却不会自动调整。 - Bubu
更新的答案是,当有新消息添加时,你可以使用scrolltoend函数。 - Mehran Khan
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接