键盘消失后保留inputAccessoryView可见

37

我想要做的是创建类似iPad上Safari“在页面上查找”搜索功能的东西。

我使用一个UIToolbar和其中的一些项目,并将其设置为UITextField上的inputAccessoryView,并与键盘连接。这个方法非常好用,但有一件事我搞不明白。在Safari中,当您搜索某些内容时,键盘会消失,但工具栏仍然留在屏幕底部。

有人知道如何实现这一点吗?我能想到的唯一解决方法是响应键盘消失事件,然后拉出UIToolbar并创建一个自定义动画将其移动到屏幕底部。但这很hacky。我正在寻找更优雅的解决方案。需要一些可以让我决定在键盘消失时该怎么处理输入附件视图的东西。

5个回答

61

操作步骤如下:

将你的 UIToolbar 分配给视图控制器中的一个属性:

@property (strong, nonatomic) UIToolbar *inputAccessoryToolbar;

在您的顶部视图控制器中添加以下方法:

- (BOOL)canBecomeFirstResponder{

    return YES;

}

- (UIView *)inputAccessoryView{

    return self.inputAccessoryToolbar;

}

然后(通常情况下不应该必要),每当键盘隐藏时,只需调用:

[self becomeFirstResponder];

这样,你的inputAccessoryToolbar将会是你的视图控制器和文本视图的输入附件视图。


1
它似乎在iOS8上无法工作,我收到了UIViewControllerHierarchyInconsistency错误,有什么想法吗? - MegaManX
2
它在我的iOS 8上可以工作,所以我可能需要一个代码示例。 - arik
1
刚刚创建了一个新的示例项目,通过Storyboard在底部添加了一个视图,为其创建了输出口,并在inputAccessoryView方法中返回该视图...我得到了与我的项目中相同的错误。 - MegaManX
我为iOS8打开了一个新的问题,你可以在这里找到它:https://dev59.com/Tofca4cB1Zd3GeqPoNU2 - MegaManX
这太完美了! - Baran Emre
显示剩余4条评论

8

我最后得到了一个未被分配为输入附属视图的UIToolBar,它在UIKeyboardWillShowNotification/UIKeyboardWillHideNotification上滑动。


谢谢,我想这确实是唯一的方法。 - Tom van Zummeren
1
这也是我目前正在做的,来到这里希望有另一种解决方案。不过我猜没有了 :( - Brad Moore
2
@BradMoore,还有另一种解决方案。请查看我的答案。 - arik
这个解决方案是否与可交互地关闭键盘的表视图一起使用? - thetrutz

5

根据之前的回答,将代码更新为Swift 4。如果你通过故事板添加工具栏,则可以这样做。

class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    @IBOutlet var toolbar: UIToolbar!

    override var canBecomeFirstResponder: Bool {
        get {
            return true
        }
    }

    override var inputAccessoryView: UIView {
        get {
            return self.toolbar
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        textField.inputAccessoryView = toolbar
    }
}

在这种情况下,无论何时文本字段放弃第一响应者,它都将默认第一响应者为主视图。请记住,如果有多个UI元素并且第一响应者在放弃后默认为不需要的视图,则可能希望明确放弃第一响应者,并将主视图设置为第一响应者。

4

在@arik的回答基础上,这里是Swift版本:

class ViewController: UIViewController {

  @IBOutlet var textField: UITextField!      

  // Input Accessory View
  private var inputAccessoryToolbar: UIToolBar?
  override func canBecomeFirstResponder() -> Bool {
    return true
  }
  override var inputAccessoryView: UIView? {
    return inputAccessoryToolbar
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    inputAccessoryToolbar = UIToolbar(frame: CGRectMake(0, 0, view.frame.size.width, 50))
    textField.inputAccessoryView = inputAccessoryToolbar
  }

  // UITextFieldDelegate
  func textFieldShouldReturn(textField: UITextField) -> Bool {
    becomeFirstResponder()
    return true
  }
}

感谢您提供的干净解决方案!

在Swift 3/4中,canBecomeFirstResponderinputAccessoryView现在是属性而不是函数/方法。 - Anjan Biswas

1

您可能还需要解决与inputAccessoryView有关的错误,因为它不尊重安全区域边距,因此在iPhone X上无法为home指示器腾出空间: iPhone X如何处理视图控制器inputAccessoryView?

我发现当您从xib获取UIToolbar并将其用作文本字段的inputAccessoryView时,最简单的解决方案是在覆盖的inputAccessoryView中返回包含UIView的工具栏,并通过safeAreaInsets.bottom使包含UIView更高。 (其他解决方案建议在子类中将工具栏底部约束到安全区域,但这会导致约束冲突,并且意味着工具栏下面的区域颜色不正确。)但是,您还必须记住,即使屏幕上没有键盘(例如如果存在外部键盘),文本字段也可以聚焦,因此您需要在这种情况下将文本视图的inputAccessoryView更改为此工具栏内的UIView。实际上,始终使用包含视图并适当调整其大小可能会使事情更简单。无论如何,这是我的inputAccessoryView覆盖:

    override var inputAccessoryView: UIView? {

    if toolbarContainerView == nil {

        let frame=CGRect(x: toolBar.frame.minX, y: toolBar.frame.minY, width: toolbar.frame.width, height: toolBar.frame.height+view.safeAreaInsets.bottom)

        toolbarContainerView = UIView(frame: frame)

    }

    if (toolbar.superview != toolbarContainerView) {

        //this is set to false when the toolbar is used above the keyboard without the container view

        //we need to set it to true again or else the toolbar will appear at the very top of the window instead of the bottom if the keyboard has previously been shown.

        toolbar.translatesAutoresizingMaskIntoConstraints=true

        toolbarContainerView?.addSubview(toolbar)

    }

    return toolbarContainerView

}

如果需要调整 toolbarContainerView 的大小,那么覆盖 viewSafeAreaInsetsDidChange 可能是一个好主意。


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