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给私有属性赋值的方式修改,但是我试过一次是无效的,也不知为什么。下来再研究研究。

遇到的问题:
屏幕快照 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 <UIKit/UIKit.h>

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


@protocol YWKeyboardDelegate <NSObject>

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

@end






@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;


@property (nonatomic, weak)id<YWKeyboardDelegate>       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 ()<YWKeyboardDelegate>

@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<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容