【问题标题】:Add a view on top of the keyboard using InputAccessoryView使用 InputAccessoryView 在键盘顶部添加视图
【发布时间】:2016-06-11 21:36:41
【问题描述】:

我正在尝试添加一个 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: '

任何帮助将不胜感激!

【问题讨论】:

标签: ios swift accessoryview


【解决方案1】:

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

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

【讨论】:

  • 谢谢。我在 viewDidLoad() 中编写了这段代码,但出现错误 - 使用未解析的标识符“textField”
  • 我把答案澄清了一点@user101010。
  • 只需将随机文本字段添加到我的故事板中的 viewController 并使用它?
  • 只有当UITextFieldUITextView 出现在屏幕上并获得焦点时,才能显示键盘。因此,您需要将其连接到屏幕上的任何文本字段或文本视图。
  • 知道了。现在我得到了与我在问题中提到的完全相同的错误。也许这与我要连接的文本字段位于滚动视图内有关?
【解决方案2】:

对您的代码进行的更改:

  • accessoryView一个高度
  • 删除 var myView: customUIView 和整个 viewDidLoad() 覆盖

【讨论】:

    【解决方案3】:

    详情

    • Xcode 11.2 (11B52)、Swift 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 布局问题

    结果



    【讨论】:

    • 我完全实现了你的代码,但我遇到了一个有趣的错误。正如你所写的,我不能标签禁用按钮,但它们会显示出来。但是,我可以选项卡启用按钮,但它们没有显示。所以它需要完全相反。需要看到启用的按钮,反之亦然
    • 抱歉,我不认为我理解您的问题。你想实现什么功能?
    • 我不想实现任何东西。我只是面临一个问题。禁用按钮的文本完全可见,但我看不到启用按钮的文本。当我选中启用按钮时,我可以看到需要反之亦然的文本。如果我用 UIImage 更改文本,一切正常。
    • 这是一个很棒的实现荣誉!
    【解决方案4】:

    试试这个。

    override var inputAccessoryView: UIView? {
        get {
           return containerView
        }
    }
    override var canBecomeFirstResponder: Bool {
       return true
    }
    

    【讨论】:

    • 这个答案可能会因为格式不好且没有解释而被折叠。
    猜你喜欢
    • 2019-11-18
    • 2015-01-28
    • 2021-09-12
    • 2017-07-30
    • 2014-03-05
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多