简体   繁体   English

停止键盘在打开时隐藏 UITextField

[英]Stop Keyboard From Hiding UITextField When Open

寻找一种解决方案,无论 UITextField 在视图层次结构中的位置,也不管其他 UI 元素,它在打开时阻止 UITextField 被键盘隐藏。

There are plenty of solutions online for adjusting your view so that a UITextField isn't hidden behind the keyboard when it appears however, I couldn't find a "one size fits all" kind of solution so had to adapt a lot of answers and make my own.网上有很多解决方案可以调整您的视图,以便 UITextField 在出现时不会隐藏在键盘后面,但是,我找不到“一刀切”的解决方案,因此不得不调整很多答案和做我自己的。 This is the solution I came up with.这是我想出的解决方案。 Hopefully it helps someone :)希望它可以帮助某人:)

First of all, this solution assumes that your "primary parent" or "top level" view is a UIScrollView or descendant (eg UITableView or UICollectionView).首先,此解决方案假定您的“主要父级”或“顶级”视图是 UIScrollView 或后代(例如 UITableView 或 UICollectionView)。 This will not work if you don't have a UIScrollView in your hierarchy as this is what is used to scroll the UITextField into position.如果您的层次结构中没有 UIScrollView,这将不起作用,因为这是用于将 UITextField 滚动到位的内容。 Other solutions show you how to scroll any UIView but when you think about it, if you need to scroll your UITextField into position, chances are your view should be scrollable anyway to stop it from going off the screen.其他解决方案向您展示了如何滚动任何 UIView 但当您考虑它时,如果您需要将 UITextField 滚动到位,您的视图可能无论如何都应该是可滚动的,以阻止它离开屏幕。

Create the extension method below.创建下面的扩展方法。 This searches for subviews of subviews (etc.) that match the given query and returns them as an array.这将搜索与给定查询匹配的子视图(等)的子视图,并将它们作为数组返回。 We'll use this later.我们稍后会用到它。

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();
}

Add the below method to your UIViewController.将以下方法添加到您的 UIViewController。 This finds the top level UIScrollView from the view hierarchy.这会从视图层次结构中找到顶级 UIScrollView。 There should only be one result.应该只有一个结果。

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;
}

Add the below event handlers.添加以下事件处理程序。 We'll register these with observers next.接下来我们将向观察者注册这些。

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

Add these 2 fields to your UIViewController.将这 2 个字段添加到您的 UIViewController。 By keeping an object reference to the observers we can unregister them later when the UIViewController is no longer visible.通过保持对观察者的对象引用,我们可以稍后在 UIViewController 不再可见时取消注册它们。

private NSObject _keyboardWillShowObserver, _keyboardWillHideObserver;

In ViewWillAppear (or wherever you register your event handlers) add these 2 lines.在 ViewWillAppear(或您注册事件处理程序的任何地方)添加这两行。 These register the observers and keep an object reference so we can unregister later.这些注册观察者并保留一个对象引用,以便我们以后可以取消注册。

_keyboardWillShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, Keyboard_Appear);
_keyboardWillHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, Keyboard_Disappear);

In ViewWillDisappear (or wherever you unregister your event handlers) add these 2 lines.在 ViewWillDisappear(或您取消注册事件处理程序的任何地方)添加这两行。 These unregister the observers from the UIViewController so they no longer respond to events.这些从 UIViewController 取消注册观察者,因此它们不再响应事件。

NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardWillShowObserver);
NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardWillHideObserver);

To clarify a few things:澄清几点:

  • This solution works when your UITextField is a subview many layers down (even a UITableViewCell or UICollectionViewCell).当您的 UITextField 是向下许多层的子视图(甚至是 UITableViewCell 或 UICollectionViewCell)时,此解决方案有效。
  • This solution does take into account any modifications made to the keyboard view.此解决方案确实考虑了对键盘视图所做的任何修改。 For example: if you add a "done" button to the top of your keyboard this will be calculated.例如:如果您在键盘顶部添加一个“完成”按钮,这将被计算。
  • The scroll adjustment is animated.滚动调整是动画的。
  • This solution does work in different orientations.此解决方案确实适用于不同的方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM