ios - 打开时停止键盘隐藏 UITextField
问题描述
寻找一种解决方案,以阻止 UITextField 在打开时被键盘隐藏,无论 UITextField 在视图层次结构中的位置以及其他 UI 元素如何。
解决方案
在线有很多解决方案可以调整您的视图,以便 UITextField 在出现时不会隐藏在键盘后面,但是,我找不到“一刀切”的解决方案,因此不得不调整很多答案和做我自己的。这是我想出的解决方案。希望它可以帮助某人:)
首先,此解决方案假定您的“主要父级”或“顶级”视图是 UIScrollView 或后代(例如 UITableView 或 UICollectionView)。如果您的层次结构中没有 UIScrollView,这将不起作用,因为这是用于将 UITextField 滚动到位的内容。其他解决方案向您展示了如何滚动任何 UIView,但是当您考虑它时,如果您需要将 UITextField 滚动到位,那么您的视图可能无论如何都应该是可滚动的,以阻止它离开屏幕。
在下面创建扩展方法。这将搜索与给定查询匹配的子视图(等)的子视图,并将它们作为数组返回。我们稍后会使用它。
public static UIView[] Find(this UIView view, Func<UIView, bool> query)
{
if (view == null)
return null;
var views = new List<UIView>();
if (query.Invoke(view))
views.Add(view);
foreach (var subview in view.Subviews)
{
var foundViews = subview.Find(query);
if (foundViews != null)
views.AddRange(foundViews);
}
return views.ToArray();
}
将以下方法添加到您的 UIViewController。这会从视图层次结构中找到顶级 UIScrollView。应该只有一个结果。
private UIScrollView FindAdjustmentScrollView()
{
var scrollViews = View.Find(v => v is UIScrollView && v.FindSuperviewOfType(View, typeof(UIScrollView)) == null);
return scrollViews.Length > 0 ? scrollViews[0] as UIScrollView : null;
}
添加以下事件处理程序。接下来我们将向观察者注册这些。
private void Keyboard_Appear(NSNotification notification)
{
var firstResponder = View.Find(v => v.IsFirstResponder).FirstOrDefault();
var scrollView = FindAdjustmentScrollView();
if (firstResponder == null || scrollView == null || !(notification.UserInfo[UIKeyboard.FrameEndUserInfoKey] is NSValue value))
return;
var keyboardBounds = value.CGRectValue;
var firstResponderAbsoluteFrame = firstResponder.Superview.ConvertRectToView(firstResponder.Frame, View);
// This is how much of a gap you would like there to be between the bottom of the UITextField
// and the top of the keyboard. Not mandatory but a nice touch in my experience.
var offset = 8;
var bottom = firstResponderAbsoluteFrame.Y + firstResponderAbsoluteFrame.Height + offset;
var scrollAmount = keyboardBounds.Height - (scrollView.Frame.Size.Height - bottom);
if (scrollAmount > 0)
scrollView.SetContentOffset(0, scrollView.ContentOffset.Y + scrollAmount);
}
private void Keyboard_Disappear(NSNotification notification)
{
var firstResponder = View.Find(v => v.IsFirstResponder).FirstOrDefault();
var scrollView = FindAdjustmentScrollView();
if (firstResponder == null || scrollView == null)
return;
scrollView.SetContentOffset(0, 0);
}
将这 2 个字段添加到您的 UIViewController。通过保持对观察者的对象引用,我们可以稍后在 UIViewController 不再可见时取消注册它们。
private NSObject _keyboardWillShowObserver, _keyboardWillHideObserver;
在 ViewWillAppear(或您注册事件处理程序的任何地方)中添加这两行。这些注册观察者并保留对象引用,以便我们以后可以取消注册。
_keyboardWillShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, Keyboard_Appear);
_keyboardWillHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, Keyboard_Disappear);
在 ViewWillDisappear 中(或在您取消注册事件处理程序的任何地方)添加这两行。这些从 UIViewController 注销观察者,因此它们不再响应事件。
NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardWillShowObserver);
NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardWillHideObserver);
澄清几点:
- 当您的 UITextField 是向下许多层的子视图(甚至是 UITableViewCell 或 UICollectionViewCell)时,此解决方案有效。
- 此解决方案确实考虑了对键盘视图所做的任何修改。例如:如果您在键盘顶部添加一个“完成”按钮,这将被计算出来。
- 滚动调整是动画的。
- 该解决方案确实适用于不同的方向。
推荐阅读
- c++ - 临时对象的取消引用运算符
- react-native - React Native Linking getInitialURL()在android中不起作用
- android - Android 从 RemoteViews 开始活动,但恢复活动
- mysql - 是否可以在 MySQL 的多个列中引用相同的外键?
- c# - 无法返回多个值..System.ValueTuple 相关问题
- jquery - 通过ajax调用保存数据后对话框未关闭
- python - 如何获取特定行的任何表的主键值
- spring - 在两个状态机中重用 Submachine
- docker - 从 hashcorp vault 填充 kubernetes configmap
- python-3.x - ValueError: 0 不在列表中