UISwitch值更改事件在UITextField编辑结束之前触发

时间:2018-11-20 14:22:20

标签: ios uitextfield uikit uiswitch uicontrolevents

在我的应用程序中,UISwitch列表中显示了许多UITextFieldUITableViewCell

当用户开始编辑UITextField然后点击UISwitch时,事件的顺序使UITextField显示UISwitch的值,因为事件处理程序未收到UITextField的结束编辑事件。

如何可靠地确保UIControlEventEditingDidEnd的{​​{1}}事件在UITextField的{​​{1}}之前触发?

它会导致如下错误(在文本字段中显示的switch值):

UISwitch and UITextField

步骤(应该发生的事情):

1。点击UIControlEventValueChanged将其激活

UISwitch

2。点击UISwitch开始编辑

UISwitch:startEditing:switch243
UISwitch:valueChanged:{true}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{true}

3。点击UITextField将其停用

UITextField:startEditing:textfield455

控制台日志(实际发生的情况-UISwitch事件在UITextField:endEditing之前触发):

UISwitch

实施:

UITextField:endEditing UISwitch:startEditing:switch243 UISwitch:valueChanged:{false} UISwitch:endEditing UIEventHandler:saveValue:switch243:{false}

UISwitch:startEditing:switch243
UISwitch:valueChanged:{true}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{true}
UITextField:startEditing:textfield455
UISwitch:startEditing:switch243
UISwitch:valueChanged:{false}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{false}
UITextField:endEditing

UITableViewCellWithSwitch.h

@interface UITableViewCellWithSwitch : UITableViewCell
@property (nonatomic, strong) NSString *attributeID;
@property (nonatomic, retain) IBOutlet UISwitch *switchField;
@end

UITableViewCellWithSwitch.m

@implementation UITableViewCellWithSwitch
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self.switchField addTarget:self
                            action:@selector(switchChanged:)
                  forControlEvents:UIControlEventValueChanged];
    }
    return self;
}
// UIControlEventValueChanged
- (void)switchChanged:(UISwitch *)sender {
    NSLog(@"UISwitch:startEditing:%@",self.attributeID);
    [self handleStartEditingForAttributeID:self.attributeID];

    NSString* newValue = sender.on==YES?@"true":@"false";
    NSLog(@"UISwitch:valueChanged:{%@}", newValue);
    [self handleValueChangeForEditedAttribute:newValue];

    NSLog(@"UISwitch:endEditing");
    [self handleEndEditingForEditedAttribute];
}
@end

UITableViewCellWithTextField.h

@interface UITableViewCellWithTextField : UITableViewCell<UITextFieldDelegate>
@property (nonatomic, strong) NSString *attributeID;
@property (strong, nonatomic) IBOutlet UITextField *inputField;
@end

UITableViewCellWithTextField.m汇总所有UI编辑事件:

@implementation UITableViewCellWithTextField
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self.inputField addTarget:self
                            action:@selector(textFieldDidBegin:)
                  forControlEvents:UIControlEventEditingDidBegin];

        [self.inputField addTarget:self
                            action:@selector(textFieldDidChange:)
                  forControlEvents:UIControlEventEditingChanged];

        [self.inputField addTarget:self
                            action:@selector(textFieldDidEnd:)
                  forControlEvents:UIControlEventEditingDidEnd];
    }
    return self;
}
// UIControlEventEditingDidBegin
-(void) textFieldDidBegin:(UITextField *)sender {
    NSLog(@"UITextField:startEditing:%@",self.attributeID);
    [self handleStartEditingForAttributeID:self.attributeID];
}
// UIControlEventEditingChanged
-(void) textFieldDidChange:(UITextField *)sender {
    NSLog(@"UITextField:valueChanged:{%@}", sender.text);
    [self handleValueChangeForEditedAttribute:sender.text];
}
// UIControlEventEditingDidEnd
-(void) textFieldDidEnd:(UITextField *)sender {
    NSLog(@"UITextField:endEditing");
    [self handleEndEditingForEditedAttribute];
}
@end

2 个答案:

答案 0 :(得分:1)

如果我的理解正确,那么您遇到的问题就是在文本字段作为第一响应者的同时更改开关值时,文本字段的文本将更新为开关的值。

UITextField的{​​{1}}事件仅在文本字段退出第一响应者时发生。如果您要做的只是确保当开关值更改时文本字段结束编辑,那么当开关接收到didEndEditing:事件时,您应该向活动文本字段发送endEditing:消息。

现在如何在文本字段上调用UIControlEventValueChanged消息取决于类的结构。您可以在表视图单元格类上有一个指定的初始化方法,在其中传递与控制文本字段的endEditing:对应的UITextField的实例。保持对文本字段实例的弱引用,然后在切换值更改时调用UISwitch。或者,您可以尝试在触发endEditing:事件或[self endEditing:YES];时在UITableViewCellWithSwitch上调用switchChanged:。我更喜欢前一种解决方案,而不是后者,因为后者更像是一种技巧,而不是适当的解决方案。

更新:

查看代码后,您在问题中提到的错误原因

  

它会导致如下错误(在文本字段中显示的switch值):

是下面的代码:

[self.superview endEditing:YES];

您正在使用开关的值调用- (void)switchChanged:(UISwitch *)sender { NSLog(@"UISwitch:startEditing:%@",self.attributeID); [self handleStartEditingForAttributeID:self.attributeID]; NSString* newValue = sender.on==YES?@"true":@"false"; NSLog(@"UISwitch:valueChanged:{%@}", newValue); [self handleValueChangeForEditedAttribute:newValue]; NSLog(@"UISwitch:endEditing"); [self handleEndEditingForEditedAttribute]; } ,而该开关的值实际上只能保存文本字段的值。在handleValueChangeForEditedAttribute:类中,您正在使用UIEventHandler方法中的switch值更新数据访问对象(DAO)。将handleEndEditingForEditedAttribute方法的逻辑更改为以下内容:

switchChanged:

在您的- (void)switchChanged:(UISwitch *)sender { if (sender.on == YES) { [self handleStartEditingForAttributeID:self.attributeID]; } else { [self handleEndEditingForEditedAttribute]; } } 类中,取消注释帖子中的“可能的解决方案”注释行。那应该确保在存储新UIEventHandler的值之前保存所有以前的更改。

attributeID

答案 1 :(得分:0)

我迄今为止最好的解决方案是解决UIEventHandler.m中的问题。如果在调用startEditing时尚未触发endEditing事件,则从UIEventHandler调用该事件。

-(void) handleStartEditingForAttributeID:(NSString *)attributeID { 
    // Possible solution   
    if (self.editedAttributeID != nil && [attributeID isEqualToString:self.editedAttributeID]==NO) { // Workaround needed for UISwitch events
        [self handleEndEditingForActiveAttribute];
    }
    self.editedAttributeID = attributeID;
    self.temporaryValue = nil;
}

-(void) handleValueChangeForEditedAttribute:(NSString *)newValue {
    self.temporaryValue = newValue;
}

-(void) handleEndEditingForEditedAttribute { 
    if (self.temporaryValue != nil) { // Only if value has changed
        NSLog(@"UIEventHandler:saveValue:%@:{%@}", self.editedAttributeID, self.temporaryValue);

        // Causes the view to regenerate
        // The UITextField loses first responder status and UIControlEventEditingDidEnd is gets triggered too late
        [self.storage saveValue:self.temporaryValue 
                   forAttribute:self.editedAttributeID];

        self.temporaryValue = nil;
    }
    self.editedAttributeID = nil;
}