[iOS] 實現(xiàn)鍵盤彈出滾動視圖上移

如圖恩沛,要搭建這么一個找回密碼頁面:


image.png

用的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)鍵盤彈出視圖上移
相比之下我的方法代碼量太多且容易出錯贬蛙。
嗯雨女,就是出錯了,我要記錄一下

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末速客,一起剝皮案震驚了整個濱河市戚篙,隨后出現(xiàn)的幾起案子五鲫,更是在濱河造成了極大的恐慌溺职,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件位喂,死亡現(xiàn)場離奇詭異浪耘,居然都是意外死亡,警方通過查閱死者的電腦和手機塑崖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門七冲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人规婆,你說我怎么就攤上這事澜躺。” “怎么了抒蚜?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵掘鄙,是天一觀的道長。 經(jīng)常有香客問我嗡髓,道長操漠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任饿这,我火速辦了婚禮浊伙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘长捧。我一直安慰自己嚣鄙,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布串结。 她就那樣靜靜地躺著哑子,像睡著了一般廓八。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赵抢,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天剧蹂,我揣著相機與錄音,去河邊找鬼烦却。 笑死宠叼,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的其爵。 我是一名探鬼主播冒冬,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摩渺!你這毒婦竟也來了简烤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤摇幻,失蹤者是張志新(化名)和其女友劉穎横侦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绰姻,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡枉侧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了狂芋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榨馁。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帜矾,靈堂內(nèi)的尸體忽然破棺而出翼虫,到底是詐尸還是另有隱情,我是刑警寧澤屡萤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布珍剑,位于F島的核電站,受9級特大地震影響灭衷,放射性物質(zhì)發(fā)生泄漏次慢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一翔曲、第九天 我趴在偏房一處隱蔽的房頂上張望迫像。 院中可真熱鬧,春花似錦瞳遍、人聲如沸闻妓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽由缆。三九已至注祖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間均唉,已是汗流浹背是晨。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留舔箭,地道東北人罩缴。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像层扶,于是被迫代替她去往敵國和親箫章。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容