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

Posted

技术标签:

【中文标题】iOS 如何使 inputaccessoryview 中的文本视图成为第一响应者?【英文标题】:iOS How to make a text view which is in an inputaccessoryview a first responder? 【发布时间】:2018-06-11 10:20:38 【问题描述】:

我想要一个附件视图中的文本视图,但附件视图只有在我按下滚动视图中的按钮时才可见,并且键盘应该与滑动时的文本视图交互关闭。解决办法是什么?

Facebook messenger 和 WhatsApp 做同样的事情,但即使在键盘关闭时它们也可以看到附件视图,但我不想要它。

我的解决方案:我让附件视图透明,而 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)!)
            
        
    


   

【问题讨论】:

【参考方案1】:

一种解决方法可能是 使用 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)
    

结果

【讨论】:

【参考方案2】:

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

【讨论】:

以上是关于iOS 如何使 inputaccessoryview 中的文本视图成为第一响应者?的主要内容,如果未能解决你的问题,请参考以下文章

iOS:如何使 UIWebView 50% 透明?

如何使用 AutoLayout (iOS/Xamarin.iOS) 使 ScrollView 适合其内容?

如何使iOS FBSDKProfilePictureView 圆形?

如何在 iOS 中使定位更准确?

如何使socket.io只连接一次

如何使 iOS 7 应用向后兼容?