美文网首页iOS菜鸟级开发iOS学习与文字有关的
UITextField一箩筐——输入长度限制、自定义placeh

UITextField一箩筐——输入长度限制、自定义placeh

作者: Wang66 | 来源:发表于2016-06-15 22:54 被阅读1295次

    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
    
    

    相关文章

      网友评论

      • 823d9dbb4818:这种做法并不能兼容第三方键盘,因为键盘输入模式对第三方键盘难以判断准确
        Wang66:@likegoto 那有没有更好的做法?
      • iOSNoteByNiu:解决方案非常好,感谢楼主的分享,已经点赞 :+1:
        Wang66:@veryGood 共勉🙌🏻
        iOSNoteByNiu:@Wang66 不用客气,希望以后多发点这种好东西,一直在关注你 :smile:
        Wang66:@veryGood 谢谢~
      • CoderJohnny:全是抄的
        Wang66:@CoderJohnny 这几个问题常见的解决方案基本就这样的。

      本文标题:UITextField一箩筐——输入长度限制、自定义placeh

      本文链接:https://www.haomeiwen.com/subject/velxdttx.html