iOS如何使inputaccessoryview中的文本视图成为第一响应者?

时间:2018-06-11 10:20:39

标签: ios swift keyboard inputaccessoryview

我想要在配件视图中使用textview,但只有当我在滚动视图中按下按钮时,配件视图才能显示,并且键盘应与滑动时的文本视图交互关闭。解决方案是什么?

Facebook Messenger& WhatsApp做同样的事情,但即使键盘关闭,他们也可以看到配件视图,但我不想要它。

我的解决方案:我使附件视图透明,textview是scrollview的子视图,我将textview定位在透明附件视图的正上方,因此它看起来像附件视图。但是当我这样做时,textview是不可触摸的,因为附件视图窗口在它上面。

我的代码:

class ViewController: UIViewController, CustomKeyboardProtocol {

let textView = UITextView()
let button = UIButton()
let scrollView = UIScrollView()

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.backgroundColor = .black

    scrollView.contentSize = CGSize(width: 10000, height: 10000)
    scrollView.keyboardDismissMode = .interactive
    scrollView.backgroundColor = .blue
    self.view.addSubview(scrollView)

    button.backgroundColor = .green
    button.frame = CGRect(x: 20, y: 20, width: 30, height: 30)
    button.addTarget(self, action: #selector(keyboard), for: .touchUpInside)
    scrollView.addSubview(button)

    textView.backgroundColor = .yellow
    textView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 40)
    self.view.addSubview(textView)
    textView.isHidden = true

    let accessoryView = CustomKeyboardAccessoryView(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
    accessoryView.keyboardDelegate = self
    accessoryView.backgroundColor = .clear
    textView.inputAccessoryView = accessoryView
}

func keyboardFrameChanged(frame: CGRect) {
    textView.frame = CGRect(x: 0, y: frame.origin.y, width: UIScreen.main.bounds.size.width, height: 40)
}

@objc func keyboardWillShow(notification: Notification) {
    if let keyboardFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        let keyboardHeight = keyboardFrame.size.height
        print("keyboard height: \(keyboardHeight)")
        textView.frame = CGRect(x: 0, y: UIScreen.main.bounds.size.height - keyboardHeight, width: UIScreen.main.bounds.size.width, height: 40)
    }
}

@objc func keyboardWillHide() {
    textView.isHidden = true
    textView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 0)
}

@objc func keyboard() {
    if textView.isFirstResponder {
        textView.resignFirstResponder()
        textView.isHidden = true
    } else {
        textView.becomeFirstResponder()
        textView.isHidden = false
    }
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    scrollView.frame = UIScreen.main.bounds
}

override var canBecomeFirstResponder: Bool {
    return true
}
}

protocol CustomKeyboardProtocol : NSObjectProtocol {
    func keyboardFrameChanged(frame : CGRect)
}

class CustomKeyboardAccessoryView: UIView {



weak var keyboardDelegate: CustomKeyboardProtocol? = nil

override func willMove(toSuperview newSuperview: UIView?) {
    if newSuperview == nil {
        self.superview?.removeObserver(self, forKeyPath: "center")
    }
    else{
        newSuperview?.addObserver(self, forKeyPath: "center", options: [NSKeyValueObservingOptions.new, NSKeyValueObservingOptions.initial], context: nil)
    }
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let theChange = change as [NSKeyValueChangeKey : AnyObject]? {
        if theChange[NSKeyValueChangeKey.newKey] != nil {
            if self.keyboardDelegate != nil && self.superview?.frame != nil {
                self.keyboardDelegate?.keyboardFrameChanged(frame: (self.superview?.frame)!)
            }
        }
    }


   }
}

2 个答案:

答案 0 :(得分:0)

可能有一种解决方法 使用textView属性只是切换键盘,但将其隐藏在键盘方法中,如此

  @objc func keyboard() {
        if textView.isFirstResponder {
            textView.resignFirstResponder()
            textView.isHidden = true
        } else {
            textView.becomeFirstResponder()
            textView.isHidden = true
        }
    }

创建单独的视图customView并将其添加到textView的inputAccessoryView(上面提到的textView)

 textView.inputAccessoryView = customViewTV

在customViewTV中添加单独的textView作为子视图并使用此

   func createCustomTV(text: String) {
        customViewTV = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 44))
        customViewTV.backgroundColor = UIColor.red
        let acceTextView = UITextView()
        acceTextView.text = text
        acceTextView.frame = CGRect(x: 0, y: 0, width: customViewTV.frame.width, height: customViewTV.frame.height)
        acceTextView.center = customViewTV.center
        acceTextView.textColor = .black
        customViewTV.addSubview(acceTextView)
    }

<强>结果

enter image description here

答案 1 :(得分:0)

OSX:我需要一个文本字段及其功能-易于选择等,因此我这样做:

fileprivate class URLField: NSTextField {
    override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)
        if let textEditor = currentEditor() {
            textEditor.selectAll(self)
        }
    }

    convenience init(withValue: String?) {
        self.init()

        if let string = withValue {
            self.stringValue = string
        }
        self.lineBreakMode = NSLineBreakMode.byTruncatingHead
        self.usesSingleLineMode = true
    }

    override func viewDidMoveToWindow() {
        // MARK: this gets us focus even when modal
        self.becomeFirstResponder()
    }
}

并像这样使用:

    // Create urlField
    let urlField = URLField(withValue: "It's a small world after all")
    urlField.frame = NSRect(x: 0, y: 0, width: 300, height: 20)
    alert.accessoryView = urlField