当 inputAccessoryView 出现时移动集合视图聊天
Posted
技术标签:
【中文标题】当 inputAccessoryView 出现时移动集合视图聊天【英文标题】:move collection view chats up when inputAccessoryView appears 【发布时间】:2018-07-13 06:19:37 【问题描述】:我正在使用聊天屏幕,其中有一个InputAccessoryView
,其中用户键入消息,UICollectionView
包含聊天。
当用户在 UICollectionView 中发送它时,我想显示最新的聊天消息。
问题是当用户键入消息时 InputAccessoryView 出现在键盘上,而 UICollectionView 落后于键盘,因此最新消息不可见。
当键盘出现时,我想将 UICollectionView 移动到键盘高度。
我正在使用以下代码。
这将为键盘隐藏和显示事件注册观察者。
func handleKeyBoard()
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
@objc func keyboardWillShow(notification: NSNotification)
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
var contentInset = self.collectionView?.contentInset
contentInset?.bottom = keyboardSize.height
self.collectionView?.contentInset = contentInset!
if self.messages.count > 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:
self.view.layoutIfNeeded()
, completion: (completed:Bool) in
let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
)
在上面的函数中,当键盘出现时,我得到它的高度总是 50 我不知道为什么可能是因为InputAccessoryView
。
获得键盘高度后,我将增加 50 个高度作为 InputAccessoryView
的高度,然后更改 contentInset
的 UICollectionViewController
并在完成动画时滚动到最后一条消息,该消息会将 UICollectionViewController 滚动到它的最后一条消息。
但这并没有发生。
这是 UICollectionView 的默认 contentInset
。
UIEdgeInsets(top: 8, left: 0, bottom: 52, right: 0)
之后
var contentInset = self.collectionView?.contentInset
contentInset?.bottom = keyboardSize.height
self.collectionView?.contentInset = contentInset!
contentInset 变成这个。
UIEdgeInsets(top: 8, left: 0, bottom: 52, right: 0)
一旦键盘隐藏,以下将为collectionview设置默认Inset
@objc func keyboardWillHide(notification: NSNotification)
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
self.collectionView?.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 52, right: 0)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:
self.view.layoutIfNeeded()
, completion: (completed:Bool) in
)
谁能帮我找到正确的方法来做到这一点。这将非常有帮助。 几乎所有聊天应用程序都具有此功能,当他们键入时,可以在聊天视图中看到一条新消息。
谢谢。
【问题讨论】:
像IQKeyboardManager这样的库可以用来处理此类问题 【参考方案1】:最好的方法是给collectionView和InputAccessoryView添加约束,这样collectionview的bottomview附加到accessory view,accessory view附加到super view的底部。
下一步在你的.m文件中设置底部空间约束的出口,调用scrollViewBottomSpace并添加以下代码。 Constrain 将为您完成工作。
#pragma mark - 键盘通知
- (void)addObservers
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
- (void)removeObservers
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
#pragma mark - Keyboard notification handlers
- (void)keyboardWillShow:(NSNotification *)notification
if(_keyboardIsVisible) return;
CGFloat height = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
[UIView animateWithDuration:0.2 animations:^
scrollViewBottomSpace.constant = height+40;
completion:^(BOOL finished)
];
_keyboardIsVisible = YES;
- (void)keyboardWillHide:(NSNotification *)notification
if(!_keyboardIsVisible) return;
[UIView animateWithDuration:0.2 animations:^
scrollViewBottomSpace.constant = 0;
completion:^(BOOL finished)
];
_keyboardIsVisible = NO;
【讨论】:
我没有使用任何故事板。我也在使用UICollectionViewControll
,所以UICollectionView
的约束是默认设置的。对于InputAccessoryView
,我也没有设置任何约束,默认情况下它会出现。 self.autoresizingMask = .flexibleHeight
我只将此属性设置到 InputAccessoryView
的视图中,它会根据其中的内容调整它的高度。
当第一次聊天屏幕出现时,keyboardWillShow 方法会自动调用,那时我得到了实际的键盘高度。但在那之后,当我点击inputAccessoryView
输入消息并出现键盘时,它给出的高度为50,与inputAccessoryView
高度相同。这意味着我没有得到键盘的实际高度。【参考方案2】:
这很简单,如果您使用UICollectionViewController
,则无需自己管理contentInset
,只需让CollectionViewController
自己处理即可,您只需在您使用时向下滚动即可'textView' 或 'textField' 成为第一响应者或当您发送消息时
要向下滚动collectionView
,只需使用此功能
func scrollToBottom()
let numberOfSections = self.collectionView!.numberOfSections
if numberOfSections > 0
let numberOfRows = self.collectionView!.numberOfItems(inSection: numberOfSections - 1)
if numberOfRows > 0
let indexPath = IndexPath(row: numberOfRows-1, section: (numberOfSections-1))
self.collectionView!.scrollToItem(at: indexPath, at: .bottom, animated: true)
【讨论】:
let indexPath = IndexPath(item: self.messages.count - 1, section: 0) self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
这两行与您的建议相同。
第一行获取最后一个项目索引,第二行滚动到该行底部对齐,以便您在 inputAccessoryView 顶部的单元格,我不明白您想知道什么?
你好@Amr 问题是UIKeyboardFrameBeginUserInfoKey
因为这个我没有得到键盘的实际高度。而不是我使用了这个UIKeyboardFrameEndUserInfoKey
,现在我可以获得键盘的高度。剩下的问题是当KeyboardWillHide
方法被调用时,它会自动调用KeyboardWillShow
,但此时在KeyboardWillShow
方法中键盘高度是 50 不是实际高度。
所以如果高度超过 50,我会添加一个约束,然后更改 UICollectionViewInsets
这是我发布的解决方案。 solution【参考方案3】:
在这个thread 我已经回答了这个问题,问题在于UIKeyboardFrameBeginUserInfoKey
而不是我使用的UIKeyboardFrameEndUserInfoKey
【讨论】:
以上是关于当 inputAccessoryView 出现时移动集合视图聊天的主要内容,如果未能解决你的问题,请参考以下文章
如何在 inputAccessoryView 内的 UILabel 中使用 AutoScrollLabel?
UITextField 的 InputAccessoryView 在旋转时消失
调用“reloadInputViews”后 inputAccessoryView 不会自动出现