当键盘覆盖输入字段但在它们之间留出一些空间时向上移动视图
Posted
技术标签:
【中文标题】当键盘覆盖输入字段但在它们之间留出一些空间时向上移动视图【英文标题】:Move a view up when the keyboard covers an input field but with leaving some space between them 【发布时间】:2016-03-26 14:19:38 【问题描述】:说明
当其中一个在编辑期间被键盘覆盖时,我想向上滚动一些 UITextField。这里有很多关于 SO 的答案,有很多风格:移动视图(通过改变它的框架),修改约束,使用 UIScrollView 和 UITableView,或者使用 UIScrollView 和修改 contentInset。
我决定使用最后一个。这个也是described by Apple,有一个Swift version on SO,还有一个described on this blog,包括一个sample project on the GitHub。
部分代码
override func viewDidLoad()
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
func textFieldShouldReturn(textField: UITextField) -> Bool
textField.resignFirstResponder()
return true
func textFieldDidEndEditing(textField: UITextField)
self.activeField = nil
func textFieldDidBeginEditing(textField: UITextField)
self.activeField = textField
func keyboardWillShow(notification: NSNotification)
if let activeField = self.activeField, keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect = self.view.frame
aRect.size.height -= keyboardSize.size.height
if (!CGRectContainsPoint(aRect, activeField.frame.origin))
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
func keyboardWillBeHidden(notification: NSNotification)
let contentInsets = UIEdgeInsetsZero
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
问题
我只想要一个简单的修改 - 在键盘和已编辑字段之间留出更多空间。因为开箱即用,它看起来像这样:
我在scrollRectToVisible
调用中修改了CGRect
,但它没有任何改变。更重要的是,即使用scrollRectToVisible
注释掉这行也没有任何效果——一切都和以前一样(包括向上滚动内容)。在 ios 9.2 上检查
如果需要,复制很简单 - 只需使用上面的 GitHub 链接下载工作代码并注释掉 scrollRectToVisible 行。
经过测试的解决方法
我尝试了解决方法,但不喜欢最终效果:
增加contentInset
- 用户可以向上滚动超过 contentSize
将UIKeyboardDidShowNotification
替换为UIKeyboardWillShowNotification
,添加另一个UIKeyboardDidShowNotification
观察者,里面只有scrollRectToVisible
- 可以,但是有两个向上滚动的动画,看起来不太好。
问题
为什么更改contentInset
(没有scrollRectToVisible
调用)会滚动scrollView 中的内容?我没有在任何文档中看到有关此类行为的信息
更重要的是 - 怎么做,再向上滚动一点,在编辑的文本字段和键盘之间留出一些空间?
我错过了什么?有什么简单的方法可以解决吗?或者使用scrollView.contentSize
而不是contentInset
会更好?
【问题讨论】:
【参考方案1】:我还没有找到为什么scrollRectToVisible
在上述情况下不起作用,但是我找到了其他可行的解决方案。在最底部提到的Apple文章Managing the Keyboard中有一个提示
还有其他方法可以在滚动视图中滚动编辑区域 在一个模糊的键盘上方。而不是改变底部的内容 滚动视图的插图,您可以扩展内容的高度 按键盘高度查看,然后滚动编辑的文本 对象进入视野。
下面的解决方案完全基于扩展内容视图的高度 (scrollView.contentSize
)。它考虑了键盘隐藏时的方向变化和向后滚动。按要求工作 - 在活动字段和键盘之间有一些空间,请参见下图
工作代码
我已将完整的工作代码放在 GitHub 上:ScrollViewOnKeyboardShow
var animateContenetView = true
var originalContentOffset: CGPoint?
var isKeyboardVisible = false
let offset : CGFloat = 18
override func viewDidLoad()
super.viewDidLoad()
for case let textField as UITextField in contentView.subviews
textField.delegate = self
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: #selector(ViewController.keyboardWillBeShown(_:)), name: UIKeyboardWillShowNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(ViewController.keyboardWillBeHidden(_:)), name: UIKeyboardWillHideNotification, object: nil)
func textFieldShouldReturn(textField: UITextField) -> Bool
textField.resignFirstResponder()
return true
func textFieldDidEndEditing(textField: UITextField)
self.activeField = nil
func textFieldDidBeginEditing(textField: UITextField)
self.activeField = textField
func keyboardWillBeShown(notification: NSNotification)
originalContentOffset = scrollView.contentOffset
if let activeField = self.activeField, keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
var visibleRect = self.scrollView.bounds
visibleRect.size.height -= keyboardSize.size.height
//that's to avoid enlarging contentSize multiple times in case of many UITextFields,
//when user changes an edited text field
if isKeyboardVisible == false
scrollView.contentSize.height += keyboardSize.height
//scroll only if the keyboard would cover a bottom edge of an
//active field (including the given offset)
let activeFieldBottomY = activeField.frame.origin.y + activeField.frame.size.height + offset
let activeFieldBottomPoint = CGPoint(x: activeField.frame.origin.x, y: activeFieldBottomY)
if (!CGRectContainsPoint(visibleRect, activeFieldBottomPoint))
var scrollToPointY = activeFieldBottomY - (self.scrollView.bounds.height - keyboardSize.size.height)
scrollToPointY = min(scrollToPointY, scrollView.contentSize.height - scrollView.frame.size.height)
scrollView.setContentOffset(CGPoint(x: 0, y: scrollToPointY), animated: animateContenetView)
isKeyboardVisible = true
func keyboardWillBeHidden(notification: NSNotification)
scrollView.contentSize.height = contentView.frame.size.height
if var contentOffset = originalContentOffset
contentOffset.y = min(contentOffset.y, scrollView.contentSize.height - scrollView.frame.size.height)
scrollView.setContentOffset(contentOffset, animated: animateContenetView)
isKeyboardVisible = false
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
coordinator.animateAlongsideTransition(nil) (_) -> Void in
self.scrollView.contentSize.height = self.contentView.frame.height
deinit
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
notificationCenter.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
【讨论】:
这适用于文本字段。进行必要的更改后,文本视图是另一回事。以上是关于当键盘覆盖输入字段但在它们之间留出一些空间时向上移动视图的主要内容,如果未能解决你的问题,请参考以下文章