当TextField,TextView和背景点击但丢失事件时,Swift iOS -Remove View

时间:2017-08-25 21:00:35

标签: swift uiview uitextfield uitextview uitapgesturerecognizer

enter image description here enter image description here

首先让我说我玩程序化,但我现在是新手。

我有程序化视图和故事板对象的混合:

StoryBoard对象:

  1. 按钮
  2. 的TextField
  3. 的TextView
  4. 程序化观点:

    1. messageLabel
    2. viewForMessageLabel
    3. 当我按下按钮时,添加了viewForMessageLabel。在viewDidLoad我添加了一个点击手势,以便在点按背景时删除viewForMessageLabel。我还将相同的点按手势添加到textField,以移除viewForMessageLabel(如果它存在)。我再次向textField添加相同的点击手势以将其删除。

      如果键盘存在,我会在viewDidLoad中向textField添加另一个点击手势以解除它。我注意到事情很古怪,我失去了触摸事件。

      如果我在触摸背景时按下按钮添加标签,它就不会被解雇。如果我按下textField,它将关闭它并显示键盘。如果再次按下按钮,textField仍然处于启动状态,标签出现,我再次按下textField,没有任何反应。当我按下返回以隐藏键盘(我实现了方法)时,键盘消失,按下按钮,出现viewForMessageLabel,现在当我按下textField时viewForMessageLabel消失。基本上,textField也会发生同样的事情。

      我想要的是

      1. 如果viewForMessageLabel存在,我按下背景,textField或textView,它应该会消失。

      2. 如果textField或textView的键盘存在,我按下背景键盘也会消失。

      3. 我的代码:

        class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {
        
            //MARK:- Outlets
            @IBOutlet weak var textField: UITextField!
            @IBOutlet weak var textView: UITextView!
            @IBOutlet weak var button: UIButton!
        
            let messagelabel: UILabel = {
                let label = UILabel()
                label.translatesAutoresizingMaskIntoConstraints = false
                label.text = "Pizza Pizza Pizza Pizza Pizza"
                label.font = UIFont(name: "Helvetica-Regular", size: 17)
                label.sizeToFit()
                label.numberOfLines = 0
                label.textAlignment = .center
                label.textColor = UIColor.white
                label.backgroundColor = UIColor.clear
                return label
            }()
        
            let viewForMessageLabel: UIView = {
                let view = UIView()
                view.translatesAutoresizingMaskIntoConstraints = false
                view.backgroundColor = UIColor.red
                return view
            }()
        
            //View Controller Lifecycle
            override func viewDidLoad() {
                super.viewDidLoad()
        
                textField.delegate = self
                textView.delegate = self
        
                // 0. hide viewForMessageLabel is background is tapped
                let tapGesture = UITapGestureRecognizer(target: self, action: #selector(removeViewForMessageLabel))
                view.addGestureRecognizer(tapGesture)
        
                // 1. hide viewForMessageLabel if textView is tapped
                textView.addGestureRecognizer(tapGesture)
        
                // 2. hide keyboard if background if tapped
                let hideKeyboard = UITapGestureRecognizer(target: self, action: #selector(hideKeyboardWhenBackGroundTapped))
                view.addGestureRecognizer(hideKeyboard)
        
                // 3. hide keyboard if textView is tapped
                textView.addGestureRecognizer(hideKeyboard)
        
                // 4. hide viewForMessageLabel for textField if background is tapped
                textField.addTarget(self, action: #selector(removeViewForMessageLabel), for: .editingDidBegin)
        
            }
        
            //MARK:- Button
            @IBAction func buttonPressed(_ sender: UIButton) {
                view.addSubview(viewForMessageLabel)
                setViewForMessageLabelAnchors()
                setMessageLabelAnchors()
            }
        
            //MARK:- Functions
            func setViewForMessageLabelAnchors(){
                viewForMessageLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 44).isActive = true
                viewForMessageLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
                viewForMessageLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
                viewForMessageLabel.addSubview(messagelabel)
            }
        
            func setMessageLabelAnchors(){
                messagelabel.topAnchor.constraint(equalTo: viewForMessageLabel.topAnchor, constant: 0).isActive = true
                messagelabel.widthAnchor.constraint(equalTo: viewForMessageLabel.widthAnchor).isActive = true
                viewForMessageLabel.bottomAnchor.constraint(equalTo: messagelabel.bottomAnchor, constant: 0).isActive = true
            }
        
            func removeViewForMessageLabel(){
                viewForMessageLabel.removeFromSuperview()
            }
        
            func hideKeyboardWhenBackGroundTapped(){
                textField.resignFirstResponder()
            }
        
            //MARK:- TextField Delegate
            func textFieldShouldReturn(_ textField: UITextField) -> Bool {
                view.endEditing(true)
                return true
            }
        
            func textViewDidBeginEditing(_ textView: UITextView) {
                removeViewForMessageLabel()
            }
        
            //MARK:- TextView Delegate
            func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
                if(text == "\n") {
                    textView.resignFirstResponder()
                    return false
                }
                return true
            }
        }
        

2 个答案:

答案 0 :(得分:1)

  
      
  1. 如果textField或textView的键盘存在,我按下背景键盘也会消失。
  2.   

你提出这样的条件取决于键盘当前是否显示但你的代码没有反映出来(而且它不应该)。您可以根据需要多次拨打resignFirstResponder,不会发生任何不良后果。您也可以在已删除的视图上致电removeFromSuperview(请参阅here)。

因此,我认为您可以将一个操作附加到单个手势识别器上:

var tapGesture: UITapGestureRecognizer?

override func viewDidLoad() {
    super.viewDidLoad()

    textField.delegate = self
    textView.delegate = self

    // 0. hide viewForMessageLabel is background is tapped
    tapGesture = UITapGestureRecognizer(target: self, action: #selector(removeLabelAndHideKeyboard))
    view.addGestureRecognizer(tapGesture)

    // 1. hide viewForMessageLabel if textView is tapped
    textView.addGestureRecognizer(tapGesture)
}

func removeLabelAndHideKeyboard() {
    viewForMessageLabel.removeFromSuperview()
    textField.resignFirstResponder()
}

答案 1 :(得分:1)

这并没有完全回答这个问题,但我找到了一个解决方法。如果我使用@Toddg建议的方法:

func removeLabelAndHideKeyboard() {
    viewForMessageLabel.removeFromSuperview()
    textField.resignFirstResponder()
}

它添加了将textField重新签名给极大帮助的函数。

同样在viewDidLoad里面我添加了:

textField.addTarget(self, action: #selector(removeViewForMessageLabel), for: .touchDown)

关键是使用 .touchDown 和NOT .editingDidBegin。这样我就可以在textField和textView之间来回切换,键盘会响应两者。我不得不在textView的键盘上添加另外一个-a toolBar,它上面有Done按钮以关闭textView:

    func addDoneButtonOnKeyboard(){
        let toolBar = UIToolbar()
        toolBar.sizeToFit()
        doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissKeyboard))
        toolBar.setItems([doneButton!], animated: true)
        textView.inputAccessoryView = toolBar
    }

    @objc func dismissTextViewKeyboard(){
        view.endEditing(true)
    }

这样当textView出现时我可以将其解雇。

在所有情况下,如果我按下textField,background或textView以及viewForMessageLabel,它将会消失。

如果textField是第一响应者并且它的键盘存在,我按下背景它将消失。

除了其他所有内容之外,我还没有弄清楚如何在触摸背景时关闭textView,所以我在toolBar上实现了一个Done按钮。如果我按下它并且textView的键盘存在,当它调用我添加的dismissTextViewKeyboard()函数时将被解除。两者都在底部,其他一切都在viewDidLoad中。

如果有人有更好的答案,我会投票。

class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {


    //MARK:- Outlets
    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var button: UIButton!

    let messagelabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Pizza Pizza Pizza Pizza Pizza"
        label.font = UIFont(name: "Helvetica-Regular", size: 17)
        label.sizeToFit()
        label.numberOfLines = 0
        label.textAlignment = .center
        label.textColor = UIColor.white
        label.backgroundColor = UIColor.clear
        return label
    }()

    let viewForMessageLabel: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = UIColor.red
        return view
    }()

    fileprivate var doneButton: UIBarButtonItem?

    //View Controller Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        textField.delegate = self
        textView.delegate = self

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(removeViewForMessageLabel))
        view.addGestureRecognizer(tapGesture)

        textField.addTarget(self, action: #selector(removeViewForMessageLabel), for: .touchDown)

        addDoneButtonOnKeyboard()
    }

    //MARK:- Button
    @IBAction func buttonPressed(_ sender: UIButton) {
        //removeMessage()
        view.addSubview(viewForMessageLabel)
        setBackgroundAnchors()
        setMessageAndLabelAnchors()
    }

    //MARK:- Functions
    func setBackgroundAnchors(){
        viewForMessageLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 44).isActive = true
        viewForMessageLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
        viewForMessageLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
        viewForMessageLabel.addSubview(messagelabel)
    }

    func setMessageAndLabelAnchors(){

        messagelabel.topAnchor.constraint(equalTo: viewForMessageLabel.topAnchor, constant: 0).isActive = true
        messagelabel.widthAnchor.constraint(equalTo: viewForMessageLabel.widthAnchor).isActive = true
        viewForMessageLabel.bottomAnchor.constraint(equalTo: messagelabel.bottomAnchor, constant: 0).isActive = true
    }

    func removeViewForMessageLabel(){
        viewForMessageLabel.removeFromSuperview()
        textField.resignFirstResponder()
    }

    //MARK:- TextField Delegate
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        view.endEditing(true)
        return true
    }

    func textViewDidBeginEditing(_ textView: UITextView) {
        removeViewForMessageLabel()
    }

    //MARK:- TextView Delegate
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if(text == "\n") {
            textView.resignFirstResponder()
            return false
        }
        return true
    }

    //MARK:- Additional Functions
    //add a done button to the keyboard when the textView is first responder
    fileprivate func addDoneButtonOnKeyboard(){
        let toolBar = UIToolbar()
        toolBar.sizeToFit()
        doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissTextViewKeyboard))
        toolBar.setItems([doneButton!], animated: true)
        textView.inputAccessoryView = toolBar
    }

    //dismiss the keyboard when the Done button is tapped
    @objc func dismissTextViewKeyboard(){
        view.endEditing(true)
    }
}