UITextField一箩筐——输入长度限制、自定义placeholder、键盘遮挡问题


1.输入长度限制:

错误示范:

textfield输入限制长度的需求很普遍,你看到这个需求时也许觉得这个太简单了,只需要像下面这样写就可以了。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString * toBeString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    NSLog(@"-----%@",toBeString);
    if(toBeString.length>5){
        _textfield.text = [toBeString substringToIndex:5];
        return NO;
    }
    return YES;
}

上面的写法对纯字符(英文和数字等)有效,但对中文无效。
这个代理方法触发的时机是每当在键盘上敲击了一个字符,导致了输入框中的蓝色高亮文本发生改变。string参数即为敲击的字符,也即为对高亮文本来说所发生的变化。乍看好像没什么问题:当输入的字符长度超过最大限制长度时,就从toBeString截取最大限制长度的子串。
但对于中文输入来说是存在问题的:输入框中高亮的文本并非最终显示在输入框的汉字,通过统计高亮文本的长度来限制输入汉字长度这明显是有问题的。这造成的结果是:当我想输入“喜剧之王”时,便最多只能输入"xijuz",因为这个长度统计的是高亮文本的长度,它此时已达到最大长度限制了,但实际上汉字还未超过最大限制长度,导致无法继续输入汉字,甚至一个汉字也输入不了。

怎么改善?

上面的问题在于对中文输入长度的统计方式不对,不能以高亮文本长度统计,应该以确确实实已选取,并已然显示在输入框的汉字统计。限制汉字的选取,但不限制高亮文本的变化。

但问题是,上面这个代理方法触发时机是高亮文本发生变动时,而在输入法选取汉字的动作并不会触发其执行。如此我们无法得知当前输入框已选的汉字们。

这就需要用到一个重要的通知了:UITextFieldTextDidChangeNotification,注册该通知后不仅高亮文本发生变动时触发,选取汉字时也会触发。

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(textFeildEditChanged:) name:@"UITextFieldTextDidChangeNotification"
                                               object:_textfield];

那我们来梳理一下限制控制的逻辑:

1.当输入纯字符时,只需比较toBeString的长度和最大限制长度,超出就截取toBeString的子串就行;
2.当输入汉字时,对高亮文本不做限制;对已然显示在输入框的汉字进行字数统计和限制,若超出最大限制长度就截取子串。

以上用代码实现就是:


- (void)textFeildEditChanged:(NSNotification *)notifition
{
    //  UITextField *tf = (UITextField *)notifition.object;
    
    NSString *toBeString = _textfield.text;
    NSString *lang = _textfield.textInputMode.primaryLanguage; // 键盘输入模式
    if ([lang isEqualToString:@"zh-Hans"]) // 如果输入中文
    {
        UITextRange *selectedRange = [_textfield markedTextRange];
        //获取高亮部分
        UITextPosition *position = [_textfield positionFromPosition:selectedRange.start offset:0];
        // 没有高亮选择的字,则对已输入的汉字进行字数统计和限制
        if (!position)
        {
            if (toBeString.length > 5) {
                _textfield.text = [toBeString substringToIndex:5];
            }
        }
        // 对高亮文本不做限制,因为它不是最终显示在输入框的文本。
        else
        {   
        }
    }
    // 中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
    else
    {
        if (toBeString.length > 5) {
            _textfield.text = [toBeString substringToIndex:5];
        }
    }
    
}


2.自定义placeholder:

textfield设置placeholder只需这样:_textfield.placeholder = @"请输入姓名,限制5个字";
但有时产品设计得需要个性化一点,可能需要对placeholder的字体、颜色等进行自定制。比如:

NSDictionary *attriDict = @{NSFontAttributeName:[UIFont systemFontOfSize:11],
                                NSForegroundColorAttributeName:[UIColor blackColor]};
    _textfield.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"请输入姓名,限制5个字"
                                                                       attributes:attriDict];

我看到网上也有人说可以通过KVC给私有属性赋值的方式修改,但是我试过一次是无效的,也不知为什么。下来再研究研究。

遇到的问题:
UITextField一箩筐——输入长度限制、自定义placeholder、键盘遮挡问题_第1张图片
屏幕快照 2016-06-15 22.09.16.png

当placeholder字体大小发生变化后,placeholder的文本可能不再垂直居中显示了!

解决方案:

子类化UITextField,重写placeholderRectForBounds:方法,对placeholder的偏移量进行调整。

#import "YWTextField.h"

@implementation YWTextField


//控制placeHolder的位置,左右缩20
-(CGRect)placeholderRectForBounds:(CGRect)bounds
{
    
    CGRect inset = CGRectMake(2, 6, bounds.size.width -10, bounds.size.height);
    return inset;
}


@end

3.键盘遮挡问题:

在有UITextField和UITextView的地方,就容易出现键盘遮挡问题。这里我要说的解决方案的思路是:通过系统提供的有关键盘的通知UIKeyboardWillShowNotification,UIKeyboardWillHideNotification进行全局注册观察。然后需要相应的类通过代理方法来处理键盘出现和消失时,界面上输入框上移和下移的动画。

既然是添加全局的观察,则在AppDelegate里注册通知:

#import 

typedef enum
{
    KeyBoardWillShow,  // 键盘弹出
    KeyBoardWillHide, // 键盘退回
}KeyBoardChangeType;


@protocol YWKeyboardDelegate 

- (void)ywKeyboardChangeStatus:(KeyBoardChangeType)changeType
                    beginFrame:(CGRect)beginFrame
                      endFrame:(CGRect)endFrame
                      duration:(CGFloat)duration
                keyboardHeight:(CGFloat)kbHeight
                      userInfo:(NSDictionary *)info;

@end






@interface AppDelegate : UIResponder 

@property (strong, nonatomic) UIWindow *window;


@property (nonatomic, weak)id       ywKeyboardDelegate;  // 代理


@end
#import "AppDelegate.h"
#import "HomeViewController.h"




@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    HomeViewController *homeVC = [[HomeViewController alloc] init];
    UINavigationController *homeNavC = [[UINavigationController alloc] initWithRootViewController:homeVC];
    self.window.rootViewController = homeNavC;
    [self.window makeKeyAndVisible];
    
    [self registerKeyboardNotification]; // 注册键盘弹出和退回的通知
    
    return YES;
}

- (void)registerKeyboardNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}


- (void)keyboardWillShow:(NSNotification *)notification
{
    [self ywKeyboardChangeStatus:KeyBoardWillShow userInfo:notification.userInfo];
}


- (void)keyboardWillHide:(NSNotification *)notification
{
    [self ywKeyboardChangeStatus:KeyBoardWillHide userInfo:notification.userInfo];
}


// 得到动画时间、键盘高度等信息。并调用代理方法,在相应类里的代理方法里实现输入框上移下移动画等。
- (void)ywKeyboardChangeStatus:(KeyBoardChangeType)changeType userInfo:(NSDictionary *)info
{
    CGFloat durationTime = [info[UIKeyboardAnimationDurationUserInfoKey] floatValue];
    CGFloat keyboardHeight = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
    CGRect beginFrame = [info[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect endFrame = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    
    if([self.ywKeyboardDelegate respondsToSelector:@selector(ywKeyboardChangeStatus:beginFrame:endFrame:duration:keyboardHeight:userInfo:)])
    {
        [self.ywKeyboardDelegate ywKeyboardChangeStatus:changeType beginFrame:beginFrame endFrame:endFrame duration:durationTime keyboardHeight:keyboardHeight userInfo:info];
    }
}



// 一定要记得移除通知
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

比如在登录界面需要处理键盘遮挡问题,出现键盘时账号和密码输入框会上移,避免被键盘遮挡;当键盘消失时,输入框移回原位。

#import "HomeViewController.h"
#import "AppDelegate.h"

@interface HomeViewController ()

@end

@implementation HomeViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.title = @"登录";
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    appDelegate.ywKeyboardDelegate = self; // 记得实现YWKeyboardDelegate协议
}



#pragma mark ---- ywkeyboardDelegate

- (void)ywKeyboardChangeStatus:(KeyBoardChangeType)changeType beginFrame:(CGRect)beginFrame endFrame:(CGRect)endFrame duration:(CGFloat)duration keyboardHeight:(CGFloat)kbHeight userInfo:(NSDictionary *)info
{
    if(changeType == KeyBoardWillShow){
        [UIView animateWithDuration:duration animations:^{
            self.view.transform = CGAffineTransformMakeTranslation(0, -kbHeight);
        }];
    }
    else if(changeType == KeyBoardWillHide){
        [UIView animateWithDuration:duration animations:^{
            self.view.transform = CGAffineTransformIdentity;
        }];
    }
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

@end

你可能感兴趣的:(UITextField一箩筐——输入长度限制、自定义placeholder、键盘遮挡问题)