我知道互联网上有很多关于这个问题的信息,但我被困住了。我有应用,我需要自定义UITextFields
。例如,我需要在编辑开始时更改边框颜色,或者我需要限制我可以在不同文本字段中设置的字符数。我还需要在几个文本字段中的图像,这些字段必须在左侧缩进。为了做到这一切,我决定制作自定义的UITextField类(以子类UITextField)。我从UITextField
创建了新类(实现了<UITextFieldDelegate>
)。在该课程中,我使用self.delegate = self
(这在互联网上被广泛使用,人们说它正在运行)所以我可以在我的自定义类中实现shouldChangeCharactersInRange
或textFieldShouldBeginEditing
。我的问题是,在这个配置中,我收到无限循环和应用程序重启(请参阅my question)。这来自self.delegate = self
。我理解在某些情况下我可以使用observer
,但在这种情况下我如何在课堂上实现shouldChangeCharactersInRange
?
如果我不以这种方式实现我的课程并将我的文本字段委托给我的视图控制器。我必须在我的视图控制器类中实现所有方法,在我看来这是非常难看的解决方案。
所以我的问题是如何正确实现UITextField子类?
P.S。我想我是以错误的方式做到的,但我无法弄清楚哪一个是正确的。
修改
这是我的代码:
MyCustomTextField.h
@interface MyCustomTextField : UITextField
@property (nonatomic) int maxSymbols;
@property (nonatomic) int leftIndent;
@end
MyCustomTextField.m
@interface MyCustomTextField () <UITextFieldDelegate>
@end
@implementation MyCustomTextField
- (id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
self.delegate = self;
self.clipsToBounds = YES;
[self setLeftViewMode:UITextFieldViewModeAlways];
UIImageView *imageView1 = [[UIImageView alloc]
initWithFrame:CGRectMake(0, 0, 37, 20)];
imageView1.image = [UIImage imageNamed:@"otp_back"];
self.leftView = imageView1;
}
return self;
}
- (CGRect) leftViewRectForBounds:(CGRect)bounds {
CGRect textRect = [super leftViewRectForBounds:bounds];
textRect.origin.x = 5;
return textRect;
}
这种检查最大长度的方法:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
// Restrict number of symbols in text field to "maxSymbols"
NSUInteger oldLength = [textField.text length];
NSUInteger replacementLength = [string length];
NSUInteger rangeLength = range.length;
NSUInteger newLength = oldLength - rangeLength + replacementLength;
BOOL returnKey = [string rangeOfString: @"\n"].location != NSNotFound;
return newLength <= (int)_maxSymbols || returnKey;
}
当我转到文本字段并开始从模拟器的虚拟键盘输入时,我收到无限循环并退出BAD ACCESS。这很奇怪,因为如果键盘是数字或密码类型,或者我从Mac键盘输入,我没有收到问题。
答案 0 :(得分:4)
我不同意在视图控制器中始终设置委托。当许多不同的视图控制器共享相同的文本字段行为时,使用UITextField本身作为委托有一些明显的优点,例如更干净的代码。
在iOS 8中,自我委托参考循环似乎是&#34;固定&#34;。但对于那些针对iOS 7及更低版本的用户,我们使用代理对象来绕过循环:
InputTextProxy.h:
@interface InputTextProxy : NSObject <UITextFieldDelegate>
@property (weak, nonatomic) id<UITextFieldDelegate> proxiedDelegate;
@end
InputTextProxy.m:
#import "InputTextProxy.h"
@implementation InputTextProxy
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [self.proxiedDelegate textFieldShouldReturn:textField];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
return [self.proxiedDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
}
@end
您可以根据需要添加更多回调,我们只使用以上两种。
现在在子类MyCustomTextField.m中创建一个属性:
@property (strong, nonatomic) InputTextProxy *inputProxy;
- (InputTextProxy *)inputProxy
{
if (!_inputProxy)
_inputProxy = [[InputTextProxy alloc] init];
return _inputProxy;
}
使用它来设置你的代表:
self.delegate = self.inputProxy;
self.inputProxy.proxiedDelegate = self;
答案 1 :(得分:2)
我不会在你的自定义UITextField中将委托设置为self,它不是很整洁。 我会做的只是拥有一个属性或版本的方法,当你收到代表电话时,你可以在你的控制器中调用。
基本上在你的视图控制器中:
- (void)viewDidLoad{
....
self.textField = [[CustomTextField alloc] init];
self.textField.delegate = self;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
self.textField.editMode = YES;
}
在CustomTextField中
-(void)setEditMode:(BOOL)edit{
if(edit){
self.layer.borderColor=[[UIColor redColor]CGColor];
self.layer.borderWidth= 1.0f;
}
}
答案 2 :(得分:1)
对于编辑的开始和结束,您有becomeFirstResponder
和resignFirstResponder
。这是最好的地方。覆盖并且不要忘记给超级电话打电话。对于输入操作,您必须检查文档。有两种方法,通过通知和子类。两者都提供不同程度的灵活性。