1.輸入長(zhǎng)度限制:
錯(cuò)誤示范:
textfield輸入限制長(zhǎng)度的需求很普遍搬卒,你看到這個(gè)需求時(shí)也許覺得這個(gè)太簡(jiǎn)單了,只需要像下面這樣寫就可以了翎卓。
- (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;
}
上面的寫法對(duì)純字符(英文和數(shù)字等)有效契邀,但對(duì)中文無效。
這個(gè)代理方法觸發(fā)的時(shí)機(jī)是每當(dāng)在鍵盤上敲擊了一個(gè)字符失暴,導(dǎo)致了輸入框中的藍(lán)色高亮文本發(fā)生改變坯门。string參數(shù)即為敲擊的字符,也即為對(duì)高亮文本來說所發(fā)生的變化逗扒。乍看好像沒什么問題:當(dāng)輸入的字符長(zhǎng)度超過最大限制長(zhǎng)度時(shí)古戴,就從toBeString截取最大限制長(zhǎng)度的子串。
但對(duì)于中文輸入來說是存在問題的:輸入框中高亮的文本并非最終顯示在輸入框的漢字矩肩,通過統(tǒng)計(jì)高亮文本的長(zhǎng)度來限制輸入漢字長(zhǎng)度這明顯是有問題的现恼。這造成的結(jié)果是:當(dāng)我想輸入“喜劇之王”時(shí),便最多只能輸入"xijuz"黍檩,因?yàn)檫@個(gè)長(zhǎng)度統(tǒng)計(jì)的是高亮文本的長(zhǎng)度叉袍,它此時(shí)已達(dá)到最大長(zhǎng)度限制了,但實(shí)際上漢字還未超過最大限制長(zhǎng)度刽酱,導(dǎo)致無法繼續(xù)輸入漢字喳逛,甚至一個(gè)漢字也輸入不了。
怎么改善肛跌?
上面的問題在于對(duì)中文輸入長(zhǎng)度的統(tǒng)計(jì)方式不對(duì)艺配,不能以高亮文本長(zhǎng)度統(tǒng)計(jì)察郁,應(yīng)該以確確實(shí)實(shí)已選取,并已然顯示在輸入框的漢字統(tǒng)計(jì)转唉。限制漢字的選取皮钠,但不限制高亮文本的變化。
但問題是赠法,上面這個(gè)代理方法觸發(fā)時(shí)機(jī)是高亮文本發(fā)生變動(dòng)時(shí)麦轰,而在輸入法選取漢字的動(dòng)作并不會(huì)觸發(fā)其執(zhí)行。如此我們無法得知當(dāng)前輸入框已選的漢字們砖织。
這就需要用到一個(gè)重要的通知了:UITextFieldTextDidChangeNotification
,注冊(cè)該通知后不僅高亮文本發(fā)生變動(dòng)時(shí)觸發(fā)款侵,選取漢字時(shí)也會(huì)觸發(fā)。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(textFeildEditChanged:) name:@"UITextFieldTextDidChangeNotification"
object:_textfield];
那我們來梳理一下限制控制的邏輯:
1.當(dāng)輸入純字符時(shí)侧纯,只需比較toBeString的長(zhǎng)度和最大限制長(zhǎng)度新锈,超出就截取toBeString的子串就行;
2.當(dāng)輸入漢字時(shí)眶熬,對(duì)高亮文本不做限制妹笆;對(duì)已然顯示在輸入框的漢字進(jìn)行字?jǐn)?shù)統(tǒng)計(jì)和限制,若超出最大限制長(zhǎng)度就截取子串娜氏。
以上用代碼實(shí)現(xiàn)就是:
- (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];
// 沒有高亮選擇的字拳缠,則對(duì)已輸入的漢字進(jìn)行字?jǐn)?shù)統(tǒng)計(jì)和限制
if (!position)
{
if (toBeString.length > 5) {
_textfield.text = [toBeString substringToIndex:5];
}
}
// 對(duì)高亮文本不做限制,因?yàn)樗皇亲罱K顯示在輸入框的文本贸弥。
else
{
}
}
// 中文輸入法以外的直接對(duì)其統(tǒng)計(jì)限制即可窟坐,不考慮其他語種情況
else
{
if (toBeString.length > 5) {
_textfield.text = [toBeString substringToIndex:5];
}
}
}
2.自定義placeholder:
textfield設(shè)置placeholder只需這樣:_textfield.placeholder = @"請(qǐng)輸入姓名,限制5個(gè)字";
但有時(shí)產(chǎn)品設(shè)計(jì)得需要個(gè)性化一點(diǎn),可能需要對(duì)placeholder的字體绵疲、顏色等進(jìn)行自定制哲鸳。比如:
NSDictionary *attriDict = @{NSFontAttributeName:[UIFont systemFontOfSize:11],
NSForegroundColorAttributeName:[UIColor blackColor]};
_textfield.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"請(qǐng)輸入姓名,限制5個(gè)字"
attributes:attriDict];
我看到網(wǎng)上也有人說可以通過KVC給私有屬性賦值的方式修改,但是我試過一次是無效的最岗,也不知為什么帕胆。下來再研究研究。
遇到的問題:
當(dāng)placeholder字體大小發(fā)生變化后般渡,placeholder的文本可能不再垂直居中顯示了懒豹!
解決方案:
子類化UITextField,重寫placeholderRectForBounds:
方法驯用,對(duì)placeholder的偏移量進(jìn)行調(diào)整脸秽。
#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的地方蝴乔,就容易出現(xiàn)鍵盤遮擋問題记餐。這里我要說的解決方案的思路是:通過系統(tǒng)提供的有關(guān)鍵盤的通知UIKeyboardWillShowNotification
,UIKeyboardWillHideNotification
進(jìn)行全局注冊(cè)觀察。然后需要相應(yīng)的類通過代理方法來處理鍵盤出現(xiàn)和消失時(shí)薇正,界面上輸入框上移和下移的動(dòng)畫片酝。
既然是添加全局的觀察囚衔,則在AppDelegate里注冊(cè)通知:
#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]; // 注冊(cè)鍵盤彈出和退回的通知
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];
}
// 得到動(dòng)畫時(shí)間、鍵盤高度等信息雕沿。并調(diào)用代理方法练湿,在相應(yīng)類里的代理方法里實(shí)現(xiàn)輸入框上移下移動(dòng)畫等。
- (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
比如在登錄界面需要處理鍵盤遮擋問題审轮,出現(xiàn)鍵盤時(shí)賬號(hào)和密碼輸入框會(huì)上移肥哎,避免被鍵盤遮擋;當(dāng)鍵盤消失時(shí)疾渣,輸入框移回原位篡诽。
#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; // 記得實(shí)現(xiàn)YWKeyboardDelegate協(xié)議
}
#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