即使 UITextField 为空,我也能检测到删除键吗?

发布于 2024-11-06 07:56:23 字数 86 浏览 0 评论 0原文

当 UITextField 不包含任何内容时,按键盘的删除键不会调用 UITextFieldDelegate 的任何方法。

我怎样才能检测到它?

When UITextField contains nothing, pressing the delete key of keyboard won't call any of UITextFieldDelegate's methods.

How can I detect it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

零度℉ 2024-11-13 07:56:23

我在 Swift 3 中添加这个答案以获得更完整的示例。
基本上,我需要一个 pincode 类型的视图,其中有多个文本字段,每个单元格中允许一个字符。

像这样
输入图片此处描述
首先创建 UITextField 的子类和定义新函数的协议。

protocol MYDeleteActionTextFieldDelegate {
    func textFieldDidSelectDeleteButton(_ textField: UITextField) -> Void
}
class MYDeleteActionTextField: UITextField {
    var deleteDelegate: MYDeleteActionTextFieldDelegate?
    override func deleteBackward() {
        // Need to call this before super or the textfield edit may already be in place
        self.deleteDelegate?.textFieldDidSelectDeleteButton(self)
        super.deleteBackward()
    }
}

然后,您使用新的子类创建文本字段,并在视图控制器中实现委托。就我而言,我管理数组中的文本字段以方便使用,并使用 PureLayout 布局单元格。我像这样存储它们

var pinFields = [UITextField]()

然后在 viewDidLoad() 中,我将所有 pin 字段添加到数组中,如下所示:

for _ in 1...6 {
            let field = EDFDeleteActionTextField.init(forAutoLayout: ())
            field.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
            field.delegate = self
            field.deleteDelegate = self
            field.textAlignment = .center
            field.font = UIFont.newBigTitle()
            field.textColor = UIColor.edfBlue()
            field.backgroundColor = UIColor.edfWhite()
            self.pinFields.append(field)
            self.pinView.addSubview(field)
        }

现在您只需响应所有适当的委托方法和 textFieldDidChange code> 上面添加的目标。

// MARK: UITextFieldDelegate
    func textFieldDidChange(textField: UITextField) {
        // If the user typed one character, move to the next cell.
        if (textField.text?.characters.count == 1) {
            let index = pinFields.index(of: textField)
            textField.resignFirstResponder()
            if (pinFields.count > index! + 1) {
                pinFields[index! + 1].becomeFirstResponder()
            }
        } // If they deleted the character move to previous cell
        else if (textField.text?.characters.count == 0) {
            let index = pinFields.index(of: textField)
            if (index! - 1 >= 0) {
                pinFields[index! - 1].becomeFirstResponder()
            }
        }
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if range.location > 0 {
            let index = pinFields.index(of: textField)
            // If there is already text in the text field and the next cell is empty - move the newly typed character to that cell.
            if (pinFields.count > index! + 1) {
                let nextField = pinFields[index! + 1]
                if (nextField.text?.characters.count == 0) {
                    textField.resignFirstResponder()
                    nextField.becomeFirstResponder()
                    nextField.text = string
                }
            }
            return false
        }
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return false
    }
    
    // MARK: EDFDeleteActionTextFieldDelegate
    func textFieldDidSelectDeleteButton(_ textField: UITextField) {
        // If user clicked delete, and there are no characters, move to previous cell if available.
        // If there are characters, it is handled in UITextFieldDelegate
        if (textField.text?.characters.count == 0) {
            let index = pinFields.index(of: textField)
            if (index! - 1 >= 0) {
                pinFields[index! - 1].becomeFirstResponder()
            }
            else {
                textField.resignFirstResponder()
            }
        }
    }

我将省略无聊的部分(例如布置文本字段等),因为这种通用功能在更多情况下比此 pincode 视图有用,但实现此子类和协议应该提供类似类型所需的所有功能观点并解决手头的问题(可能需要类似的东西)。

快乐编码。

I'm adding this answer for a more complete example in Swift 3.
Basically, I needed a pincode-type view where I have multiple text fields that allow one character in each cell.

like this
enter image description here
Start by creating a subclass of UITextField and a protocol that defines a new func.

protocol MYDeleteActionTextFieldDelegate {
    func textFieldDidSelectDeleteButton(_ textField: UITextField) -> Void
}
class MYDeleteActionTextField: UITextField {
    var deleteDelegate: MYDeleteActionTextFieldDelegate?
    override func deleteBackward() {
        // Need to call this before super or the textfield edit may already be in place
        self.deleteDelegate?.textFieldDidSelectDeleteButton(self)
        super.deleteBackward()
    }
}

Then you create the text fields with the new subclass and implement the delegate in your view controller. In my case, I manage the textfields in an array for ease of use and layout the cells with PureLayout. I store them like this

var pinFields = [UITextField]()

Then in viewDidLoad(), I add all the pin fields into the array like so:

for _ in 1...6 {
            let field = EDFDeleteActionTextField.init(forAutoLayout: ())
            field.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
            field.delegate = self
            field.deleteDelegate = self
            field.textAlignment = .center
            field.font = UIFont.newBigTitle()
            field.textColor = UIColor.edfBlue()
            field.backgroundColor = UIColor.edfWhite()
            self.pinFields.append(field)
            self.pinView.addSubview(field)
        }

Now you just need to respond to all the appropriate delegate methods and the textFieldDidChange target that was added above.

// MARK: UITextFieldDelegate
    func textFieldDidChange(textField: UITextField) {
        // If the user typed one character, move to the next cell.
        if (textField.text?.characters.count == 1) {
            let index = pinFields.index(of: textField)
            textField.resignFirstResponder()
            if (pinFields.count > index! + 1) {
                pinFields[index! + 1].becomeFirstResponder()
            }
        } // If they deleted the character move to previous cell
        else if (textField.text?.characters.count == 0) {
            let index = pinFields.index(of: textField)
            if (index! - 1 >= 0) {
                pinFields[index! - 1].becomeFirstResponder()
            }
        }
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if range.location > 0 {
            let index = pinFields.index(of: textField)
            // If there is already text in the text field and the next cell is empty - move the newly typed character to that cell.
            if (pinFields.count > index! + 1) {
                let nextField = pinFields[index! + 1]
                if (nextField.text?.characters.count == 0) {
                    textField.resignFirstResponder()
                    nextField.becomeFirstResponder()
                    nextField.text = string
                }
            }
            return false
        }
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return false
    }
    
    // MARK: EDFDeleteActionTextFieldDelegate
    func textFieldDidSelectDeleteButton(_ textField: UITextField) {
        // If user clicked delete, and there are no characters, move to previous cell if available.
        // If there are characters, it is handled in UITextFieldDelegate
        if (textField.text?.characters.count == 0) {
            let index = pinFields.index(of: textField)
            if (index! - 1 >= 0) {
                pinFields[index! - 1].becomeFirstResponder()
            }
            else {
                textField.resignFirstResponder()
            }
        }
    }

I'll leave out the boring parts (like laying out text fields etc), since this general functionality is useful in more cases than this pincode view, but implementing this child class and protocol should give all the functionality that you would need for similar type views and solve for the question at hand (which is probably needing something similar).

Happy coding.

浅忆 2024-11-13 07:56:23

这似乎可以通过子类化 UITextField 来实现。 UITextField 遵循名为 UITextInput 的协议,而该协议又遵循另一个名为 UIKeyInput 的协议。 UIKeyInput 协议有一个方法 deleteBackward,每次按下键盘中的退格键时都会触发该方法。

下面是它的外观

标题

#import <UIKit/UIKit.h>

@interface EmptyDeleteTextField : UITextField

@end

实现

- (void)deleteBackward
{
    NSLog_SM(@"Length: %d", (int)self.text.length);
    [super deleteBackward];
}

PS:不要忘记调用 super,因为您不想弄乱 UITextField 的默认行为。

This seems doable by subclassing UITextField. UITextField conforms to a protocol called UITextInput which inturn conforms to another protocol called UIKeyInput. UIKeyInput protocol has a method deleteBackward which fires every time the backspace key in keyboard is pressed.

Here is how it looks

Header

#import <UIKit/UIKit.h>

@interface EmptyDeleteTextField : UITextField

@end

Implementation

- (void)deleteBackward
{
    NSLog_SM(@"Length: %d", (int)self.text.length);
    [super deleteBackward];
}

PS: Don't forget to call super because you don't want to mess with the default behaviour of UITextField.

红尘作伴 2024-11-13 07:56:23

这可以通过子类化 UITextField 并将其添加为所需文本字段的自定义类来实现。
然后重写方法“deleteBackward”
此方法将捕获所有退格事件。

Swift 中的代码:

override func deleteBackward() {
        super.deleteBackward()
        // Enter your stuff here
    }

还要确保您也调用了 super 方法,因为它正在执行事件的基本功能。

This can be implemented by subclassing UITextField and adding it as custom class of desired textfield.
Then override the method "deleteBackward"
This method will catch all the backspace events.

Code in Swift:

override func deleteBackward() {
        super.deleteBackward()
        // Enter your stuff here
    }

Also make sure you that are calling super method too, as it is doing the basic functionalities of the event.

夢归不見 2024-11-13 07:56:23

好吧,我已经弄清楚了。所以在
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)范围 replacementText:(NSString *)text
委托方法(即当即将输入文本时)您只需执行 a ,

if (text.length <= 0) {
    // backspace
    return FALSE;
} else {

因为对于 backspace text.length 将 == 0,而其他所有内容都将 == 1。

Ok, I've figured it out. so in the
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
delegate method (i.e. when the text is about to be input) you simply do a

if (text.length <= 0) {
    // backspace
    return FALSE;
} else {

because for backspace text.length will == 0, and everything else it will == 1.

晨敛清荷 2024-11-13 07:56:23

可以在上面放一个按钮,但这有点脆弱,因为键盘布局可能会随着不同的 iOS 版本而改变,而且不同的语言肯定有不同的键盘布局。

请参阅“管理文本字段和文本视图”Apple 文档。我确信有办法做到这一点。它类似于 UITextField 实现一个协议来获取按键事件。这些关键事件之一可能是删除键,因此您可以覆盖接收这些事件的任何方法并以这种方式获取它。

Its possible to put a button over it, but that's a bit fragile since keyboard layout could change with different iOS versions and there certainly are different keyboard layouts for different languages.

Look at the "Managing Text Fields and Text Views" Apple doc. Im sure there is a way to do this. Its something like a UITextField implements a protocol to get keyevents. One of those key events will probably be a delete key, so you could override whatever method receives these and get it that way.

天暗了我发光 2024-11-13 07:56:23

我不确定,但您可以使用 addTarget: action: forControlEvents: 尝试自定义方法吗?尝试使用 UIControlEventAllEditingEvents 选项。

I am not sure but can you try a custom method using addTarget: action: forControlEvents:. Try the UIControlEventAllEditingEvents option.

╄→承喏 2024-11-13 07:56:23

对于第一季度。

在 Swift 4.2 中,下面对我有用

@objc func keyboardInputShouldDelete(_ textField: UITextField) -> Bool {
        print("User Pressed backspace in empty textfield ")
        return true
    }

For Q1.

In Swift 4.2 below works for me

@objc func keyboardInputShouldDelete(_ textField: UITextField) -> Bool {
        print("User Pressed backspace in empty textfield ")
        return true
    }
岁吢 2024-11-13 07:56:23

使用键盘时,显然您正在将其写入某个变量(例如:UITextField、UILabel 甚至全局字符串)

检测删除操作的选项可以是:

  • 保留全局“int previousLengthOfText”
  • 将此变量初始化为 lastLengthOfText = 0;
  • 捕获委托函数上的更改:例如:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{

  • 将 label\textField 的长度添加到此全局变量,并查看是否添加或删除了字符。

例如:

if ([self.myTextField.text length] > previousLengthOfText) {
{
// user deleted a character - Do your action here
previousLengthOfText = [self.myTextField.text length];
}

When using keypad, obviously you are writing it to some variable (e.g: UITextField, UILabel or even a global String)

An option to detect the delete action can be:

  • Keep a global "int previousLengthOfText"
  • Init this var to be lastLengthOfText = 0;
  • catch the change on the delegate function: e.g :

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{

  • compare the length of your label\textField to this global var and see if a character was added or deleted.

e.g :

if ([self.myTextField.text length] > previousLengthOfText) {
{
// user deleted a character - Do your action here
previousLengthOfText = [self.myTextField.text length];
}
仙女山的月亮 2024-11-13 07:56:23

将OP的解决方案从问题迁移到答案:

似乎没有什么简单的方法可以做到这一点。我能找到的最有用的链接是:

  1. UITextField :任何检测删除键事件的方法该字段为空?

  2. 如何获取 UITextField 中按下的实际按键

简而言之,我的解决方案是在文本字段的开头放置一个永久的空格。并进行其他必要的更改(textFieldShouldReturn:textField:shouldChangeCharactersInRange:replacementString: 等)。

Migrating OP's solution from the question to an answer:

There seems no trivial way to do it. The most useful links I can find are:

  1. UITextField : Any way to detect the Delete key event when the field is empty ?

  2. How to get the actual key pressed in a UITextField

In short, my solution is to put a permanent SPACE at the start of the text field. And make other necessary changes(textFieldShouldReturn:, textField:shouldChangeCharactersInRange:replacementString:, etc.).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文