добавить представление поверх клавиатуры с помощью InputAccessoryView swift

Я пытаюсь добавить 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:»

любая помощь будет оценена по достоинству!


person user101010    schedule 28.02.2016    source источник
comment
Вот полный ответ для будущих зрителей: это не капсула. github.com/29satnam/InputAccessoryView   -  person Codetard    schedule 27.09.2018


Ответы (4)


Сам код довольно прост, чтобы изображение оставалось над клавиатурой. Код, который вы разместили, неверен, попробуйте это (обратите внимание, что вы должны подключить 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
}
person paulvs    schedule 28.02.2016
comment
Благодарю. Я написал этот код в viewDidLoad () и получаю сообщение об ошибке - использование неразрешенного идентификатора textField - person user101010; 29.02.2016
comment
Немного уточнил ответ @ user101010. - person paulvs; 29.02.2016
comment
просто добавьте случайное текстовое поле в мой viewController в раскадровке и используйте его? - person user101010; 29.02.2016
comment
Клавиатура может отображаться, только если UITextField или UITextView отображается на экране и получает фокус. Поэтому вам нужно подключить его к любым текстовым полям или текстовым представлениям, которые у вас есть на экране. - person paulvs; 29.02.2016
comment
понятно. теперь я получаю ту же ошибку, о которой упоминал в своем вопросе. может быть, это как-то связано с тем, что текстовые поля, к которым я хочу подключиться, находятся внутри прокрутки? - person user101010; 29.02.2016
comment
Может быть, потому, что представление, которое вы добавляете в качестве вспомогательного представления ввода, уже находится в иерархии представлений? Подробнее см. stackoverflow.com/a/25882277/1305067. - person paulvs; 29.02.2016
comment
большое спасибо. removeFromSuperview работал. Теперь моя последняя проблема в том, что когда клавиатура опущена, вид исчезает. Я добавил наблюдателей для клавиатуры, которые будут показывать и скрывать. и я хочу добавить представление обратно в супервизор, когда клавиатура скрывается и что оно будет иметь те же ограничения, что и в раскадровке. любая идея? - person user101010; 29.02.2016
comment
О, так вы хотите, чтобы ваше представление было видно всегда, а не только тогда, когда видна клавиатура? Нравится приложение для чата? Тогда забудьте inputAccessoryView, это часть клавиатуры. Вам необходимо использовать уведомления клавиатуры, чтобы получать уведомления о появлении и исчезновении клавиатуры, а также о размере клавиатуры. Затем вам нужно рассчитать, как далеко прокручивать представление содержимого вашего представления прокрутки, чтобы ваше представление (которое будет в нижней части представления прокрутки) всегда было над клавиатурой. См. stackoverflow.com/questions/3546571/ - person paulvs; 29.02.2016
comment
Привет, я пошел по твоему пути и получил другие ответы ... но все еще не могу правильно настроить свое представление ... не могли бы вы увидеть этот вопрос - person Honey; 16.05.2017

Подробности

  • 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

Полученные результаты

введите описание изображения здесь


введите описание изображения здесь


введите описание изображения здесь

person Vasily Bodnarchuk    schedule 08.02.2018
comment
Я полностью реализую ваш код, но столкнулся с интересной ошибкой. Как вы писали, я не могу вкладывать кнопки с отключенными вкладками, но они отображаются. Тем не менее, я могу вкладывать кнопки с активными вкладками, но они не отображаются. Так что это должно быть полной противоположностью. Включенные кнопки должны быть видны, и наоборот - person Emre Önder; 15.03.2018
comment
Извините, я не думаю, что понимаю вашу проблему. Какой функционал вы хотите реализовать? - person Vasily Bodnarchuk; 15.03.2018
comment
Я не хочу ничего реализовывать. Просто столкнулся с проблемой. Тексты отключенных кнопок видны полностью, но я не вижу текстов включенных кнопок. Когда я вкладываю кнопки с активными вкладками, я вижу тексты, которые должны быть наоборот. Если я меняю тексты с помощью UIImage, все работает. - person Emre Önder; 15.03.2018
comment
Это отличная реализация! - person anoop4real; 16.01.2020

Попробуй это.

override var inputAccessoryView: UIView? {
    get {
       return containerView
    }
}
override var canBecomeFirstResponder: Bool {
   return true
}
person Hoang Anh Tuan    schedule 16.02.2019
comment
Этот ответ, вероятно, будет сброшен из-за плохого форматирования и отсутствия объяснений. - person 0xInfection; 16.02.2019

Изменения, которые необходимо внести в ваш код:

  • Дайте accessoryView высоту
  • Удалить var myView: customUIView и все viewDidLoad() переопределение
person ma11hew28    schedule 13.12.2016