Swift iOS - 当 TextField、TextView 和背景被点击但丢失事件时删除视图
Posted
技术标签:
【中文标题】Swift iOS - 当 TextField、TextView 和背景被点击但丢失事件时删除视图【英文标题】:Swift iOS -Remove View When TextField, TextView, and Background Tapped But Losing Events 【发布时间】:2017-08-25 21:00:34 【问题描述】:首先让我说我玩过程序化,但我目前是新手。
我混合了程序化视图和情节提要对象:
故事板对象:
-
按钮
文本字段
文本视图
程序化视图:
-
消息标签
viewForMessageLabel
当我按下按钮时,viewForMessageLabel
被添加。在viewDidLoad
中,我添加了一个点击手势以在点击背景时删除viewForMessageLabel
。我还将相同的点击手势添加到 textField 以删除 viewForMessageLabel
(如果存在)。我再次将相同的点击手势添加到 textField 以将其删除。
如果键盘存在,我会在 viewDidLoad
中向 textField 添加另一个轻击手势以将其关闭。我注意到事情很古怪,我失去了联系事件。
如果我在触摸背景时按下按钮添加标签,它不会被关闭。如果我按下 textField 它将关闭它并显示键盘。如果我再次按下按钮 textField 仍然处于启动状态,标签会出现,我再次按下 textField 并且没有任何反应。当我按回车键隐藏键盘时(我实现了该方法),键盘消失,按下按钮,viewForMessageLabel
出现,现在当我按下 textField 时,viewForMessageLabel
消失。基本上同样的事情发生在 textField 上。
我想要的是
如果 viewForMessageLabel
存在并且我按下背景、textField 或 textView,它应该会消失。
如果 textField 或 textView 的键盘存在并且我按下背景,则键盘也会消失。
我的代码:
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
【问题讨论】:
你有很多重叠的点击手势识别器。我不确定水龙头是否默认通过。看起来你有点过于复杂了。 @toddg 谢谢。我刚刚读了一篇文章,说我可以在同一个水龙头上添加另一个动作。我要试试。你为什么说我把事情复杂化了? 【参考方案1】:如果 textField 或 textView 的键盘存在并且我按下背景,则键盘也应该消失。
您呈现此内容的前提是当前是否显示了键盘,但您的代码并未反映这一点(也不应该)。您可以根据需要多次拨打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()
【讨论】:
感谢您的帮助!我会在几个小时后回家尝试一下?? 告诉我结果如何。 我试过了,但它不起作用。首先我在其中键入委托方法,然后我将它们注释掉(然后取消注释它们)。当键盘存在并且我点击背景时,没有任何反应。当键盘和 viewForMessageLabel 都存在并且我点击 bg 时没有任何反应。在两者仍然存在的情况下,我点击 textField 并且视图仍然存在。唯一删除视图的是 textView。我 c+p 你写的内容并在 viewDidLoad 中注释掉了其他所有内容 我认为这可能是因为UITextField
已经有手势识别器。现在我的问题是,当用户点击文本字段时,为什么要隐藏键盘
大声笑你的权利我看过了,smh。我只是在玩它。如果我使用: tapGesture = ... 和 func removeLabelAndHideKeyboard() viewForMessageLabel.removeFromSuperview() textField.resignFirstResponder() 我可以点击背景或 textView 并且视图将消失。如果选择了 textField 并且我点击了 bg,则键盘将消失。现在这里有 2 个问题: 1. 如果我点击 textView 并触摸背景,键盘会停留。 2.如果视图存在并且我点击文本字段视图不会消失【参考方案2】:
这并不能完全回答问题,但我找到了解决方法。如果我使用@Toddg 建议的方法:
func removeLabelAndHideKeyboard()
viewForMessageLabel.removeFromSuperview()
textField.resignFirstResponder()
它为函数添加了对文本字段的签名,这对我们有很大帮助。
我还在 viewDidLoad 里面添加了:
textField.addTarget(self, action: #selector(removeViewForMessageLabel), for: .touchDown)
关键是使用 .touchDown 而不是 .editingDidBegin。这样我就可以在 textField 和 textView 之间来回切换,键盘会同时响应两者。我必须再添加 1 个东西 - 一个工具栏到 textView 的键盘上,它上面有完成按钮来关闭 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,因此我在工具栏上实现了一个完成按钮。如果我按下它并且 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)
【讨论】:
以上是关于Swift iOS - 当 TextField、TextView 和背景被点击但丢失事件时删除视图的主要内容,如果未能解决你的问题,请参考以下文章
Swift:仅当键盘隐藏 TextField 或 Button 时滚动视图
Swift iOS - TextField 初始宽度错误的底部边框
损坏的内联 datePicker 作为 TextField Swift iOS 14 的 InputView
获取 Button 和 Textfield 数据,当它们在 swift 5 中以编程方式添加时