一、我们通常在设计登录界面时会用到UITextField,如下图所示:
通常想实现下面几点:
1、左边显示图片
2、textField中添加默认的占位符(提示文字),并且希望占位符和左边图片有一点的距离,或者让占位符居中,
3、点击textField输入时光标的位置应该紧在占位符左侧,并紧挨着占位符
最终实现效果如下图所示:
4.如何更好地限制一个UITextField的输入长度
二、左边显示图片很简单下面几行代码搞定(右边显示图片同理):
UIImageView *passwordImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"passwordIcon"]];
password.leftView = passwordImage;
password.leftViewMode = UITextFieldViewModeAlways;
提示:上下两个图片的宽度要保持一致,不然会导致占位符的左边无法对其!
三、而设置占位符的位置和编辑状态时光标的位置试了很多方法感觉都不好使,最终找到一个方法,自定义一个basicTextField继承自UITextField;然后可以重写下面的几个方法:
- (CGRect)borderRectForBounds:(CGRect)bounds;
- (CGRect)textRectForBounds:(CGRect)bounds;
- (CGRect)placeholderRectForBounds:(CGRect)bounds;
- (CGRect)editingRectForBounds:(CGRect)bounds;
- (CGRect)clearButtonRectForBounds:(CGRect)bounds;
- (CGRect)leftViewRectForBounds:(CGRect)bounds;
- (CGRect)rightViewRectForBounds:(CGRect)bounds;
四、下面是具体的代码实现:
(1)设置左视图
- (CGRect)leftViewRectForBounds:(CGRect)bounds{
CGRect iconRect = [super leftViewRectForBounds:bounds];
iconRect.origin.x += 10;
return iconRect;
}
(2)重写占位符的x值
- (CGRect)placeholderRectForBounds:(CGRect)bounds{
CGRect placeholderRect = [super placeholderRectForBounds:bounds];
placeholderRect.origin.x += 1;
return placeholderRect;
}
(3)重写文字输入时的X值
- (CGRect)editingRectForBounds:(CGRect)bounds{
CGRect editingRect = [super editingRectForBounds:bounds];
editingRect.origin.x += 20;
return editingRect;
}
(4)重写文字显示时的X值
- (CGRect)textRectForBounds:(CGRect)bounds{
CGRect textRect = [super editingRectForBounds:bounds];
textRect.origin.x += 20;
return textRect;
}
第四个问题:如何更好地限制一个UITextField的输入长度
要限制一个UITextField的输入字数(参考链接),首先想到的应该是通过
UITextFieldDelegate
的代理方法来限制
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
比如要设置字数限制为20:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == self.titleField) {
if (textField.length > 20) return NO;
}
return YES;
}
但是这样的限制简单粗暴,可能会影响用户正常逻辑下的输入,比如输入了20个字符后,要退格回删字符。
这时候我们可能会考虑“Detect backspace in UITextField”,比如简单地判断replacementString的长度是否为0。
接着我们可能还会遇到用户已经输入20个字符了,这时候继续输入---不过是选择了部分文本进行替换-----无法进行了,这也妨碍了用户的正常操作,所以限制的代码版本可能会演进为:
#pragma mark - UITextFieldDelegate
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == self.titleField) {
if (string.length == 0) return YES;
NSInteger existedLength = textField.text.length;
NSInteger selectedLength = range.length;
NSInteger replaceLength = string.length;
if (existedLength - selectedLength + replaceLength > 20) {
return NO;
}
}
return YES;
}
到这里可能会觉得基本大功告成了,但是当你输入19个字符后,第20个字符以中文汉字的形式继续输入,那么系统会在键盘上方提供后续的一系列联想词,你会发现通过这种方式可以连续选字输入从而突破20个字符的限制。WTF
到了这里,我们可能会希望有个类似
(void)textFieldDidChange:(UITextField *)textField
的回调方法,但可惜没有。
当然,我们还可以通过(void)textFieldDidEndEditing:(UITextField *)textField;
回调方法在结束编辑的时候把文本截断,虽然在用户体验上会有点突兀。
不过当我们点进去UITextField.h头文件里寻觅上述回调方法而不得时,可能会发现最下面有这么个消息通知名称:
UIKIT_EXTERN NSString *const UITextFieldTextDidChangeNotification;
不过,监听消息还要记得解除监听,通常我还习惯把监听消息的代码统一放在一个方法中,看起来有点“大动干戈”。
所幸的是UITextField本身提供了相应的事件监听:
[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
- (void)textFieldDidChange:(UITextField *)textField
{
if (textField == self.titleField) {
if (textField.text.length > 20) {
textField.text = [textField.text substringToIndex:20];
}
}
}