嘿伙计们我很快就是新人,所以请善待!我已经编写了自己的函数来在键盘出现时向上滚动文本字段。为了通过点击文本字段来关闭键盘,我创建了一个UITapGestureRecognizer,用于在点击时关注文本字段上的第一响应者。
但是,在自动完成表中选择其中一个条目时,不会调用didSelectRowAtIndexPath。相反,看起来轻敲手势识别器正在被调用并且只是辞职第一响应者。
我猜是否有某种方法告诉点击手势识别器继续将点击消息传递到UITableView,但我无法弄清楚它是什么。在9年前的堆栈溢出的objc和帖子中只有解决方案,我想知道是否有更新的解决方案!谢谢,如果你想了解最新情况,这是我的代码:
class ChatLogController : UIViewController, UITextFieldDelegate , UITableViewDelegate , UITableViewDataSource, UIGestureRecognizerDelegate, UIImagePickerControllerDelegate ,UINavigationControllerDelegate {
var messages = [Message]()
var user : User?{
didSet{
observeMessages()
}
}
@IBOutlet weak var tabelView: UITableView!
@IBOutlet weak var messageTextField: UITextField!
@IBOutlet weak var bottomViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var currentMessageRecieverImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
configureTableView()
currentMessageRecieverImage.translatesAutoresizingMaskIntoConstraints = false;
currentMessageRecieverImage.layer.cornerRadius = 30;
currentMessageRecieverImage.layer.masksToBounds = true
currentMessageRecieverImage.contentMode = .scaleAspectFill
if let currentMessageRecieverUser = user{
currentMessageRecieverImage.loadImageUsingCacheWithUrlString(urlString: currentMessageRecieverUser.picURL!);
print(currentMessageRecieverUser.userName!)
}
tabelView.delegate = self;
tabelView.dataSource = self;
messageTextField.delegate = self;
let dragAwayFromTextGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleTapAwayFromTextEdit))
dragAwayFromTextGesture.direction = UISwipeGestureRecognizerDirection.down
dragAwayFromTextGesture.delegate = self;
tabelView.addGestureRecognizer(dragAwayFromTextGesture)
let dragBackToMessages = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipeBackToMessages))
dragBackToMessages.direction = UISwipeGestureRecognizerDirection.right
dragBackToMessages.delegate = self;
tabelView.addGestureRecognizer(dragBackToMessages)
let TapAwayFromTextEditTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapAwayFromTextEdit))
tabelView.addGestureRecognizer(TapAwayFromTextEditTapGesture)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
@objc func handleSwipeBackToMessages(){
dismiss(animated: false, completion: nil)
}
func observeMessages(){
guard let uid = Auth.auth().currentUser?.uid else{
return;
}
// ref gets user that is logged in
let ref = Database.database().reference().child("user-messages").child(uid)
ref.observe(.childAdded) { (snapshot) in
// gets needed messages
let messageId = snapshot.key
let messagesRef = Database.database().reference().child("messages").child(messageId)
messagesRef.observe(.value, with: { (snapshot) in
guard let dict = snapshot.value as? [String : AnyObject] else{
return
}
let message = Message()
message.imageUrl = dict["imageurl"] as? String
message.fromId = dict["fromid"] as? String
message.text = dict["text"] as? String
message.timestamp = dict["timestamp"] as? String
message.toId = dict["toid"] as? String
if message.chatPartnerId() == self.user?.toId{
self.messages.append(message)
}
DispatchQueue.main.async {
self.tabelView.reloadData()
}
})
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellid" , for: indexPath) as! CustomChatTableViewCell;
let gray = UIColor(red:0.94, green:0.94, blue:0.94, alpha:1.0)
let red = UIColor(red:1.00, green:0.22, blue:0.37, alpha:1.0)
let message = messages[indexPath.item]
if message.toId == user?.toId{
cell.messageBackground.backgroundColor = red
cell.messageLabel.textColor = UIColor.white
}
else{
cell.messageBackground.backgroundColor = gray
cell.messageLabel.textColor = UIColor.black
}
cell.messageLabel.text = message.text
if message.imageUrl != nil{
//print(message.imageUrl!)
// cell.messageImageView.image = UIImage(named : "user.jpg")
cell.messageImageView.loadImageUsingCacheWithUrlString(urlString: message.imageUrl!)
//print(cell.messageImageView.image.debugDescription)
cell.messageImageView.isHidden = false;
cell.messageImageView.translatesAutoresizingMaskIntoConstraints = false;
cell.messageImageView.contentMode = .scaleAspectFill
cell.messageLabel.isHidden = true
cell.messageBackground.isHidden = true;
}
else
{
cell.messageImageView.isHidden = true;
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.messageLabel.isHidden = false
cell.messageBackground.isHidden = false;
}
return cell;
}
@objc func handleTapAwayFromTextEdit(){
//print("handle tap away from text edit running ")
messageTextField.endEditing(true)
}
@IBAction func backToMessageListPressed(_ sender: Any) {
dismiss(animated: false, completion: nil)
}
@IBAction func infoButtonPressed(_ sender: Any) {
}
// saves text to fire base
@IBAction func sendButtonPressed(_ sender: Any) {
handleSendMessageToDataBase()
}
func handleSendMessageToDataBase(){
let ref = Database.database().reference().child("messages")
// needed for making list in firebase for unique texts
let childRef = ref.childByAutoId()
if messageTextField.text == ""{
return
}
if let message = messageTextField.text{
let toID = user!.toId!
let fromId = Auth.auth().currentUser!.uid
let timeStamp : Int = Int(Int(NSDate().timeIntervalSince1970))
print(timeStamp)
let values = ["text" : message , "toid" : toID , "timestamp" : "\(timeStamp)" , "fromid" : fromId]
childRef.updateChildValues(values, withCompletionBlock: { (error, ref) in
if error != nil{
print(error!)
return
}
let userMessagesref = Database.database().reference().child("user-messages").child(fromId)
let messageID = childRef.key
userMessagesref.updateChildValues([messageID: 1])
let recipientUserMessageRef = Database.database().reference().child("user-messages").child(toID)
recipientUserMessageRef.updateChildValues([messageID: 1])
})
}
messageTextField.text = ""
messageTextField.endEditing(true)
}
@IBAction func sendImageButtonPressed(_ sender: Any) {
handleSendImage()
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
print("You selected cell #\(indexPath.row)!")
}
func handleSendImage(){
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selectedImageFromPicker : UIImage?
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage{
selectedImageFromPicker = editedImage
}
else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage{
selectedImageFromPicker = originalImage
}
if let selectedImage = selectedImageFromPicker{
uploadToFireBaseUsingSelectedImage(selectedImage : selectedImage)
}
dismiss(animated: true, completion: nil)
}
private func uploadToFireBaseUsingSelectedImage(selectedImage :
UIImage){
let imageName = NSUUID().uuidString
let refToStorage = Storage.storage().reference().child("message_images").child(imageName)
if let uploadData = UIImageJPEGRepresentation(selectedImage, 0.2){
refToStorage.putData(uploadData, metadata: nil, completion: { (metaData, error) in
if error != nil{
print("failed to upload firebase image when sending in chatlogcontroller")
print(error!)
return
}
if let imageURL = metaData?.downloadURL()?.absoluteString{
self.sendMessageWithImageURL(imageURL: imageURL)
}
})
}
}
private func sendMessageWithImageURL(imageURL : String){
let ref = Database.database().reference().child("messages")
// needed for making list in firebase for unique texts
let childRef = ref.childByAutoId()
let toID = user!.toId!
let fromId = Auth.auth().currentUser!.uid
let timeStamp : Int = Int(Int(NSDate().timeIntervalSince1970))
print(timeStamp)
let values = ["imageurl" : imageURL , "toid" : toID , "timestamp" : "\(timeStamp)" , "fromid" : fromId]
childRef.updateChildValues(values, withCompletionBlock: { (error, ref) in
if error != nil{
print(error!)
return
}
let userMessagesref = Database.database().reference().child("user-messages").child(fromId)
let messageID = childRef.key
userMessagesref.updateChildValues([messageID: 1])
let recipientUserMessageRef = Database.database().reference().child("user-messages").child(toID)
recipientUserMessageRef.updateChildValues([messageID: 1])
})
}
func textFieldDidBeginEditing(_ textField: UITextField) {
UIView.animate(withDuration: 0.2, animations:{
self.bottomViewHeightConstraint.constant = 308;
self.view.layoutIfNeeded()
})
}
func textFieldDidEndEditing(_ textField: UITextField) {
UIView.animate(withDuration: 0.2, animations:{
self.bottomViewHeightConstraint.constant = 50;
self.view.layoutIfNeeded()
})
}
func configureTableView()
{
tabelView.delegate = self;
tabelView.dataSource = self;
tabelView.register(UINib(nibName: "MessageCell" , bundle : nil), forCellReuseIdentifier: "customMessageCell");
tabelView.allowsSelection = true;
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self);
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let message = messages[indexPath.item]
if message.imageUrl != nil{
return 200
}
return (CGFloat((message.text?.count)! + 70) )
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
handleSendMessageToDataBase()
return true
}
}
答案 0 :(得分:2)
解决方法是将cancelsTouchesInView
的属性TapAwayFromTextEditTapGesture
设置为false
。这将导致它将触摸传递给表视图。
来自Apple documentation on this property(我强调):
当此属性为true(默认设置)并且接收器识别其手势时,待处理的触摸不会传递给视图以及之前发送的触摸通过发送到视图的touchesCancelled(_:with :)消息取消。如果手势识别器无法识别其手势,或如果此属性的值为false,则视图将接收多点触控序列中的所有触摸。
答案 1 :(得分:0)
另外两种方法:
在UITextViewDelegate
中,在开始编辑时启用手势识别器,在结束编辑时将其禁用。您也可以在键盘事件处理方法中启用它,并在手势识别器调用的方法中禁用它。
将手势识别器指定为代理人,并在代理人询问手势识别器是否应接收触摸事件时检查键盘是否已启动。