【发布时间】:2019-04-23 00:28:15
【问题描述】:
在我的应用程序中,UITableViewCells 列表中显示了许多 UISwitches 和 UITextFields。
当用户开始编辑 UITextField 然后点击 UISwitch 时,事件的顺序会导致 UITextField 显示 UISwitch 的值,因为事件处理程序没有收到结束编辑事件UITextField 的。
如何可靠地确保UITextField 的UIControlEventEditingDidEnd 事件在UISwitch 的UIControlEventValueChanged 之前被触发?
它会导致这样的错误(文本字段中显示的开关值):
步骤(应该发生什么):
1.点击UISwitch激活它
UISwitch:startEditing:switch243
UISwitch:valueChanged:{true}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{true}
2.点击UITextField开始编辑
UITextField:startEditing:textfield455
3.点击UISwitch将其停用
UITextField:endEditing
UISwitch:startEditing:switch243
UISwitch:valueChanged:{false}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{false}
控制台日志(实际发生的情况 - UISwitch 事件在 UITextField:endEditing 之前触发):
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:
@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
UIEventHandler.m 聚合所有 UI 编辑事件:
-(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;
}
【问题讨论】:
-
您需要提供有关您的代码在做什么的更多信息。从您所显示的内容来看,点击开关以“停用它”除了执行两个日志语句之外没有任何作用。见minimal reproducible example
-
你想在Switch上实现什么?
-
@MohammadSadiq 我需要按
UIEventHandler.m使用的每个输入字段类型(开始编辑、更改值、结束编辑)调用 3 个事件 -
@PeterGerhat - 当您只发布部分代码时,任何人都很难提供帮助。例如,现在你有两个
textFieldDidBegin方法?此外,没有任何迹象表明sender.attributeID来自哪里? -
@DonMag 在问题中添加了更多详细信息。这是一个关于 UIKit 中的事件处理的问题,特别是 UISwitch 和 UITextField。不想让它太宽泛。
标签: ios uitextfield uikit uiswitch uicontrolevents