序言:
我為什么要寫這篇文章?或許我自己就是一個懶人,我初學iOS的時候瘋狂使用github上面的各種開源庫,當時的想法是這東西太牛逼了,怎么做的,但每每我去深入源碼,又只好因為自己的水平有限而淺嘗則止.但正是由于人類這種特有的惰性而造就了各種好用的工具,從蒸汽機到現(xiàn)在滿大街的汽車,從萊特兄弟的第一架飛機到現(xiàn)在的各種直升機 民用客機..........或許我沒有那么牛逼,我依然希望自己能跟上前人的腳步,這也是我學習走路的一個過程.還有一個原因是,這是@花早同學很久之前提供的想法,我只是將他用代碼實現(xiàn).也許你會說UITextFiled有什么好搞的,不是切菜的東西嗎?但是我依然想對這個小控件進行封裝,因為這是我從MJ老師那里學到的,寫一個更好用 ,更方便我們編程的工具,如果這個這個小東西能省去你一分鐘的時間,我就十分欣慰了,如有不妥當?shù)牡胤较M魑荒艽蠓街赋?
課前準備:
由于這個小東西是基于runtime實現(xiàn)的,所以我們有必要去了解一下runtime的關(guān)聯(lián)對象(Associated Object)這一概念,眾所周知Category是可以添加自定義方法幫助系統(tǒng)的類進行一個功能性的擴展的,但是要添加成員變量就要借助runtime了.應用關(guān)聯(lián)對象可以在運行時添加成員變量.還有一個特性就是xcode6時代就有了的關(guān)鍵字IBInspectable,在我們定義成員變量的時候用這個關(guān)鍵字去修飾,就會讓ui控件的屬性面板生成擴展,像下面這個圖:
上課!上課!
首先我們?yōu)閁ITextField寫一個category,并為其添加一個控制懶人textfiled開關(guān)的屬性sl_lazyTFOpen
@interface UITextField (SLCategory)
//是否開啟懶人版TextFiled
@property (nonatomic, assign, getter=sl_lazyTFOpen) IBInspectable BOOL lazyTFOpen;
@property (nonatomic, assign) BOOL sl_lazyTFOpen;
@implementation UITextField (SLCategory)
- (void)setSl_lazyTFOpen:(BOOL)sl_lazyTFOpen{
//OBJC_ASSOCIATION_RETAIN 宿主對象銷毀 關(guān)聯(lián)對象也會被銷毀
objc_setAssociatedObject(self, @selector(sl_lazyTFOpen), @(sl_lazyTFOpen), OBJC_ASSOCIATION_RETAIN);
}
- (BOOL)sl_lazyTFOpen{
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setLazyTFOpen:(BOOL)lazyTFOpen{
if(!lazyTFOpen) return;
self.sl_lazyTFOpen = lazyTFOpen;
//lazyTFOpen是yes進行初始化配置
[self setUPSelf];
}
在setUPSelf方法中我們要做的是監(jiān)聽textfiled的這兩個通知 UIControlEventEditingChanged和
UIControlEventEditingDidBegin
和一些對鍵盤做監(jiān)聽,用在后面的幫助textFiled躲避鍵盤的遮擋:
- (void)setUPSelf{
[self addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[self addTarget:self action:@selector(textDidBegin:) forControlEvents:UIControlEventEditingDidBegin];
self.inputAccessoryView = _toolBar;
self.textField = self;
//監(jiān)聽鍵盤點擊,
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(didClickKeyboard:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(didKboardDisappear:) name:UIKeyboardWillHideNotification object:nil];
}
以設置textFiled的內(nèi)容長度限制為例,如法炮制添加sl_max這個成員變量,每當監(jiān)聽到textfled的內(nèi)容改變時就進行長度校驗:
- (void)textFieldDidChange:(UITextField *)textField
{
if (textField == self)
{
if (textField.text.length > self.sl_max)
{
textField.text = [textField.text substringToIndex:self.sl_max];
if (self.sl_warningAnimation) {
[self shake];
}
}
}
}
這樣一來我們的內(nèi)容長度校驗就完成了,其他的控制面板屬性擴展就依樣畫葫蘆吧,或者有興趣的同學可以課后瞄一瞄我的源碼.
textFiled的天敵??
每當我的界面中的輸入框被鍵盤遮擋,就要開始加補丁了,我們得寫上那么些代碼來修復,要是這個東西能自動躲避鍵盤就好了,貌似印度佬做了這件事,但是每當我的同事因為那個庫和自己的代碼有沖突時,就不得不叫苦連天了,很幸運的是我們終于可以刪掉他了,誰叫他沒有一個開關(guān)功能呢!!
我們要思考的問題有兩個:1是我們?nèi)绾巫宼extFiled跟隨鍵盤移動,這個很簡單,當然是利用監(jiān)聽鍵盤做父view的transform動畫!2.當我們的textFiled被多個view嵌套怎么辦?答案固然是計算textFiled的實際位置啦!但是這個計算過程相對復雜 ,我們?yōu)榱撕喕缓靡雜l_superView和sl_textFiledArr這倆個變量,讓用戶自行去配置,這里要說明的是sl_superView我們希望做一個移動動畫的view,這個一般設置為根view,而sl_textFiledArr就是sl_superView的一個數(shù)組屬性,這里面裝載的是textfiled對像.到時候用戶只要這樣配置就可以使用我們的框架了:
#pragma mark -鍵盤即將跳出
-(void)didClickKeyboard:(NSNotification *)sender{
CGFloat durition = [sender.userInfo[@"UIKeyboardAnimationDurationUserInfoKey"] doubleValue];
CGRect keyboardRect = [sender.userInfo[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat keyboardHeight = keyboardRect.size.height;
[ self.sl_superView.sl_textFiledArr enumerateObjectsUsingBlock:^(UITextField *textFiled, NSUInteger idx, BOOL *stop) {
if (self==textFiled&&[textFiled isFirstResponder]) {
[UIView animateWithDuration:durition animations:^{
float h = 0;
if (self.sl_superView==self.superview) {
h = self.sl_superView.frame.size.height-textFiled.frame.origin.y-self.frame.size.height;
}else{
CGRect superVFrame = [self.superview convertRect:self.frame toView:self.sl_superView];
h = self.sl_superView.frame.size.height-textFiled.frame.origin.y-superVFrame.origin.y-self.frame.size.height;
}
if (h>keyboardHeight) {
return;
}
self.sl_superView.transform = CGAffineTransformMakeTranslation(0, h-keyboardHeight);
}];
}
}];
}
當self.superView不是self.sl_superView時進行坐標轉(zhuǎn)換并且計算sl_superView應該移動的距離,已達到躲避鍵盤的效果
設置一下開關(guān),動畫,長度限制