29

我正在尝试添加一个 uiview 始终位于键盘顶部。我首先使用 KeyboardWillShow/Hide 完成了它,但它并没有涵盖所有情况,我正在尝试使用 inputAccesoryView。这是我尝试过的:

private var accessoryView = UIView(frame: CGRectZero)

class ViewController : UIViewController {

    var myView: customUIView

    override var inputAccessoryView: UIView {
        return accessoryView
    }

    override func canBecomeFirstResponder() -> Bool {
        return true
    }

    override func viewDidLoad() {
       super.viewDidLoad()
       accessoryView = myView
    }
}

我收到以下错误:

由于未捕获的异常'UIViewControllerHierarchyInconsistency'而终止应用程序,原因:'子视图控制器:UICompatibilityInputViewController 应该有父视图控制器:MyViewController 但请求的父是:UIInputWindowController:'

任何帮助将不胜感激!

4

4 回答 4

53

为了让视图贴在键盘上方,代码本身非常简单。您发布的代码不正确,试试这个(请注意,您必须连接textFieldUITextField情节提要中的):

@IBOutlet weak var textField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    let customView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 44))
    customView.backgroundColor = UIColor.red
    textField.inputAccessoryView = customView
}
于 2016-02-28T23:29:18.237 回答
31

细节

  • Xcode 11.2 (11B52)、斯威夫特 5

解决方案

键盘工具栏按钮

import UIKit

enum KeyboardToolbarButton: Int {

    case done = 0
    case cancel
    case back, backDisabled
    case forward, forwardDisabled

    func createButton(target: Any?, action: Selector?) -> UIBarButtonItem {
        var button: UIBarButtonItem!
        switch self {
            case .back: button = .init(title: "back", style: .plain, target: target, action: action)
            case .backDisabled:
                button = .init(title: "back", style: .plain, target: target, action: action)
                button.isEnabled = false
            case .forward: button = .init(title: "forward", style: .plain, target: target, action: action)
            case .forwardDisabled:
                button = .init(title: "forward", style: .plain, target: target, action: action)
                button.isEnabled = false
            case .done: button = .init(title: "done", style: .plain, target: target, action: action)
            case .cancel: button = .init(title: "cancel", style: .plain, target: target, action: action)
        }
        button.tag = rawValue
        return button
    }

    static func detectType(barButton: UIBarButtonItem) -> KeyboardToolbarButton? {
        return KeyboardToolbarButton(rawValue: barButton.tag)
    }
}

键盘工具栏

import UIKit

protocol KeyboardToolbarDelegate: class {
    func keyboardToolbar(button: UIBarButtonItem, type: KeyboardToolbarButton, isInputAccessoryViewOf textField: UITextField)
}

class KeyboardToolbar: UIToolbar {

    private weak var toolBarDelegate: KeyboardToolbarDelegate?
    private weak var textField: UITextField!

    init(for textField: UITextField, toolBarDelegate: KeyboardToolbarDelegate) {
        super.init(frame: .init(origin: .zero, size: CGSize(width: UIScreen.main.bounds.width, height: 44)))
        barStyle = .default
        isTranslucent = true
        self.textField = textField
        self.toolBarDelegate = toolBarDelegate
        textField.inputAccessoryView = self
    }

    func setup(leftButtons: [KeyboardToolbarButton], rightButtons: [KeyboardToolbarButton]) {
        let leftBarButtons = leftButtons.map {
            $0.createButton(target: self, action: #selector(buttonTapped))
        }
        let rightBarButtons = rightButtons.map {
            $0.createButton(target: self, action: #selector(buttonTapped(sender:)))
        }
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        setItems(leftBarButtons + [spaceButton] + rightBarButtons, animated: false)
    }

    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
    @objc func buttonTapped(sender: UIBarButtonItem) {
        guard let type = KeyboardToolbarButton.detectType(barButton: sender) else { return }
        toolBarDelegate?.keyboardToolbar(button: sender, type: type, isInputAccessoryViewOf: textField)
    }
}

extension UITextField {
    func addKeyboardToolBar(leftButtons: [KeyboardToolbarButton],
                            rightButtons: [KeyboardToolbarButton],
                            toolBarDelegate: KeyboardToolbarDelegate) {
        let toolbar = KeyboardToolbar(for: self, toolBarDelegate: toolBarDelegate)
        toolbar.setup(leftButtons: leftButtons, rightButtons: rightButtons)
    }
}

用法

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        textField.addKeyboardToolBar(leftButtons:  [.back, .forwardDisabled], rightButtons:  [.done], toolBarDelegate: self)
    }
}

extension ViewController: KeyboardToolbarDelegate {
   func keyboardToolbar(button: UIBarButtonItem, type: KeyboardToolbarButton, isInputAccessoryViewOf textField: UITextField) {
        print("Tapped button type: \(type) | \(textField)")
    }
}

完整的使用示例

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        createTextField(frame: CGRect(x: 50, y: 50, width: 200, height: 40), leftButtons: [.backDisabled, .forward], rightButtons: [.cancel])
        createTextField(frame: CGRect(x: 50, y: 120, width: 200, height: 40), leftButtons: [.back, .forwardDisabled], rightButtons: [.done])
    }

    private func createTextField(frame: CGRect, leftButtons: [KeyboardToolbarButton] = [], rightButtons: [KeyboardToolbarButton] = []) {
        let textField = UITextField(frame: frame)
        textField.borderStyle = .roundedRect
        view.addSubview(textField)
        textField.addKeyboardToolBar(leftButtons: leftButtons, rightButtons: rightButtons, toolBarDelegate: self)
    }
}

extension ViewController: KeyboardToolbarDelegate {
   func keyboardToolbar(button: UIBarButtonItem, type: KeyboardToolbarButton, isInputAccessoryViewOf textField: UITextField) {
        print("Tapped button type: \(type) | \(textField)")
    }
}

Xcode 11.2 布局问题

结果

在此处输入图像描述


在此处输入图像描述


在此处输入图像描述

于 2018-02-08T21:15:44.133 回答
3

试试这个。

override var inputAccessoryView: UIView? {
    get {
       return containerView
    }
}
override var canBecomeFirstResponder: Bool {
   return true
}
于 2019-02-16T04:55:49.890 回答
1

对代码进行的更改:

  • accessoryView个高度
  • 删除var myView: customUIView和整个viewDidLoad()覆盖
于 2016-12-13T18:08:10.027 回答