如圖恩沛,要搭建這么一個找回密碼頁面:
用的UIScrollView,為了避免鍵盤遮擋輸入框廊勃,監(jiān)聽了鍵盤出現(xiàn)和消失的事件:
//增加監(jiān)聽刻伊,當(dāng)鍵盤出現(xiàn)或改變時收出消息
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
//增加監(jiān)聽盒至,當(dāng)鍵退出時收出消息
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
開始的想法是將鍵盤和響應(yīng)輸入框的frame都轉(zhuǎn)換到self.view的坐標(biāo)體系,這樣才不用考慮UIScrollView的滾動導(dǎo)致比較不準(zhǔn)的問題窗骑,用轉(zhuǎn)換后響應(yīng)輸入框的最底部Y值減去鍵盤最頂部的Y值得到需要的偏移量needOffsetY,如果needOffsetY大于0說明有重疊遮蓋部分漆枚,需要向上滾動UIScrollView
代碼如下:
- (void)keyboardWillShow:(NSNotification *)aNotification{
//獲取鍵盤的高度
NSDictionary *userInfo = [aNotification userInfo];
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [aValue CGRectValue];
// 將鍵盤和輸入框的frame都轉(zhuǎn)換到self.view的坐標(biāo)體系创译,這樣比較才準(zhǔn)確
CGRect responderConvertedFrame = [self.scrollView convertRect:self.firstResponder.frame toView:self.view];
CGRect keyboardConvertedFrame = [self.view.window convertRect:keyboardRect toView:self.view];
// 輸入框的最底部減去鍵盤的頂部就是要移動的距離
CGFloat needOffsetY = responderConvertedFrame.origin.y + responderConvertedFrame.size.height - keyboardConvertedFrame.origin.y;
// 如果要移動距離大于0說明有遮蓋,說明需要移動
if (needOffsetY > 0) {
// scrollView現(xiàn)在的偏移量 + 需要移動的偏移量 = 最終要設(shè)置的偏移量
CGFloat offsetY = needOffsetY + self.scrollView.contentOffset.y;
[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, offsetY) animated:NO];
}
}
// 鍵盤消失不用做什么
- (void)keyboardWillHide:(NSNotification *)aNotification{
}
但是運行后在最底下會兩個輸入框點擊輸入墙基,鍵盤出現(xiàn)scrollView向上滾動到恰好不遮擋輸入框软族,但是scrollView會立馬向下跳一下,導(dǎo)致鍵盤繼續(xù)遮擋住輸入框碘橘,
![Upload 鍵盤.gif failed. Please try again.]
會發(fā)現(xiàn)有時還是遮蓋住互订,這是因為此時設(shè)置的偏移量大于此時ScrollView所能設(shè)置的最大偏移量,那么這個所能設(shè)置的最大偏移量是多少呢痘拆,是ScrollView的contentSize的高減去frame的高:self.scrollView.contentSize.height - self.scrollView.height;
所以在設(shè)置scrollView偏移之前要先判斷如果如果最終要設(shè)置的偏移量小于scrollView現(xiàn)在能設(shè)置的最大偏移量仰禽,則直接設(shè)置偏移就行了
if (offsetY <= maxOffsetY) {
[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, offsetY) animated:NO];
}
否則的話否則需要需要給self.scrollView.contentInset.bottom增加一個差值,補足offsetY - maxOffsetY
如下
self.scrollView.contentInset = UIEdgeInsetsMake(self.scrollView.contentInset.top, self.scrollView.contentInset.left, self.scrollView.contentInset.bottom + ceil(offsetY - maxOffsetY), self.scrollView.contentInset.right);
但是這里我們self.scrollView.contentInset.bottom增加一個值,在鍵盤消失的時候就要減去這個值吐葵,否則scrollView的contentSize會越來越大规揪,整個頁面就瘋了。所以我們用一個屬性記錄這個差值温峭,鍵盤出現(xiàn)的時候加上猛铅,鍵盤消失的時候減去。
- (void)keyboardWillShow:(NSNotification *)aNotification{
//獲取鍵盤的高度
NSDictionary *userInfo = [aNotification userInfo];
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [aValue CGRectValue];
// 將鍵盤和輸入框的frame都轉(zhuǎn)換到self.view的坐標(biāo)體系凤藏,這樣比較才準(zhǔn)確
CGRect responderConvertedFrame = [self.scrollView convertRect:self.firstResponder.frame toView:self.view];
CGRect keyboardConvertedFrame = [self.view.window convertRect:keyboardRect toView:self.view];
// 輸入框的最底部減去鍵盤的頂部就是要移動的距離
CGFloat needOffsetY = responderConvertedFrame.origin.y + responderConvertedFrame.size.height - keyboardConvertedFrame.origin.y;
// 如果要移動距離大于0說明有遮蓋奸忽,說明需要移動
if (needOffsetY > 0) {
// scrollView現(xiàn)在的偏移量 + 需要移動的偏移量 = 最終要設(shè)置的偏移量
CGFloat offsetY = needOffsetY + self.scrollView.contentOffset.y;
// scrollView現(xiàn)在能設(shè)置的最大偏移量
CGFloat maxOffsetY = self.scrollView.contentSize.height - self.scrollView.height;
// 如果最終要設(shè)置的偏移量小于scrollView現(xiàn)在能設(shè)置的最大偏移量,則直接設(shè)置偏移就行了揖庄,否則需要需要給self.scrollView.contentInset.bottom增加一個差值栗菜,補足offsetY - maxOffsetY
// 使用一個屬性contentInsetBottom記錄差值,然后鍵盤消失的時候再把這個差值減去蹄梢,恢復(fù)scrollView原有的contentSize
if (offsetY <= maxOffsetY) {
self.contentInsetBottom = 0;
[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, offsetY) animated:NO];
}else {
self.contentInsetBottom = ceil(offsetY - maxOffsetY);
self.scrollView.contentInset = UIEdgeInsetsMake(self.scrollView.contentInset.top, self.scrollView.contentInset.left, self.scrollView.contentInset.bottom + self.contentInsetBottom, self.scrollView.contentInset.right);
[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, offsetY) animated:NO];
}
}
}
- (void)keyboardWillHide:(NSNotification *)aNotification{
self.scrollView.contentInset = UIEdgeInsetsMake(self.scrollView.contentInset.top, self.scrollView.contentInset.left, self.scrollView.contentInset.bottom - self.contentInsetBottom, self.scrollView.contentInset.right);
}
應(yīng)該完成了吧疙筹!但是細(xì)看上邊的代碼是有問題的,看第一張圖禁炒,基本上只有在確認(rèn)新密碼而咆,圖形驗證碼,短信驗證碼三個輸入框時才需要滾動視圖幕袱,上邊兩個基本不會出來遮擋暴备。那么執(zhí)行上邊的代碼重復(fù)下邊的操作就會傻逼:現(xiàn)在短信驗證碼框輸入->讓鍵盤消失->輸入手機號->讓鍵盤消失->輸入手機號->讓鍵盤消失。凹蜂。馍驯。
重復(fù)后兩步幾次就會發(fā)現(xiàn),ScrollView再也無法滾動玛痊,要不是還能點擊返回差點以為crash了
原因如下:
第一次在短信驗證碼框輸入汰瘫,scrollView的最大偏移量滿足不了需求,需要給contentInset.bottom加一個值擂煞,這個值上文我們說了記錄在屬性self.contentInsetBottom中混弥,鍵盤消失的時候再減去這個值,但是減去這個值之后應(yīng)該置為0对省,否則我輸入手機號的時候不需要滾動蝗拿,但是依然會走到鍵盤監(jiān)聽事件方法,在keyboardWillShow方法里各種判斷發(fā)現(xiàn)不需要做任何處理蒿涎,但是在鍵盤消失的時候會不斷的執(zhí)行self.scrollView.contentInset.bottom - self.contentInsetBottom
結(jié)果就是self.scrollView.contentSize.height的值不斷減小哀托,然后再也不能滾動了。
更改如下:
- (void)keyboardWillHide:(NSNotification *)aNotification{
self.scrollView.contentInset = UIEdgeInsetsMake(self.scrollView.contentInset.top, self.scrollView.contentInset.left, self.scrollView.contentInset.bottom - self.contentInsetBottom, self.scrollView.contentInset.right);
self.contentInsetBottom = 0;
}
這個傻逼問題劳秋,臨發(fā)版時才發(fā)現(xiàn)仓手,一時還沒反應(yīng)過來是什么問題胖齐,還是靠隊友另想辦法解決。真實尷尬
這里是針對滾動視圖做的處理嗽冒,對于普通UIView移動主視圖可以通過修改 self.view 的 frame呀伙、center、或者是 transform 屬性來進行變形添坊。
以transform為例剿另,拿到鍵盤的frame就知道了keyboardY,剩下只需要一行代碼就可以了:
self.view.transform = CGAffineTransformMakeTranslation(0, keyboardY - self.view.frame.size.height);
鍵盤消失的時候:
- (void)keyboardWillHide:(NSNotification *)aNotification{
[self.view endEditing:YES];
self.scrollView.transform = CGAffineTransformMakeTranslation(0, 0);
}
從這個博客里看到的[iOS] 實現(xiàn)鍵盤彈出視圖上移
相比之下我的方法代碼量太多且容易出錯贬蛙。
嗯雨女,就是出錯了,我要記錄一下