swift實現(xiàn)ios類似微信輸入框跟隨鍵盤彈出的效果

封面(圖文無關(guān))

為什么要做這個效果


在聊天app,例如微信中,你會注意到一個效果,就是在你點擊輸入框時輸入框會跟隨鍵盤一起向上彈出,當(dāng)你點擊其他地方時,輸入框又會跟隨鍵盤一起向下收回,二者完全無縫連接,那么這是怎么實現(xiàn)的呢,也許你會說直接在鍵盤彈出的時候把輸入框也向上移動不就行了?但是我使用這種方法的時候,發(fā)現(xiàn)效果十分不理想,會有明顯的滯后現(xiàn)象,原因有以下幾點:
1.鍵盤彈出動畫并不是勻速,鍵盤和輸入框的時間曲線不完全一致,運動不同步
2.各種鍵盤的高度不一樣(比如搜狗輸入法就比系統(tǒng)自帶鍵盤要高)
3.無法確定鍵盤動畫的時間,會導(dǎo)致延遲

解決方案


使用本地通知,對鍵盤的狀態(tài)(彈出、收回)進行監(jiān)控,當(dāng)鍵盤狀態(tài)發(fā)生改變時,在相應(yīng)的方法中對輸入框的位置進行操作。

這里應(yīng)用了兩種在ios編程中很重要的思想:Key-value coding (KVC) 和 key-value observing (KVO)

1.使用NSNotificationCenter.defaultCenter().addObserver()添加對UIKeyboardWillShowNotificationUIKeyboardWillHideNotification鍵的監(jiān)控,當(dāng)這些值發(fā)生改變時發(fā)送通知

    NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyBoardWillShow:", name:UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyBoardWillHide:", name:UIKeyboardWillHideNotification, object: nil)

2.實現(xiàn)兩個監(jiān)控方法

實現(xiàn)鍵盤彈出的方法:

func keyBoardWillShow(note:NSNotification)
{

    //1
    let userInfo  = note.userInfo as! NSDictionary
    //2
    var  keyBoardBounds = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
    let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    //3
    var keyBoardBoundsRect = self.view.convertRect(keyBoardBounds, toView:nil)
    //4
    var keyBaoardViewFrame = keyBaordView.frame
    var deltaY = keyBoardBounds.size.height
    //5
    let animations:(() -> Void) = {
        
        self.keyBaordView.transform = CGAffineTransformMakeTranslation(0,-deltaY)
    
    if duration > 0 {
        let options = UIViewAnimationOptions(UInt((userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).integerValue << 16))
        
        UIView.animateWithDuration(duration, delay: 0, options:options, animations: animations, completion: nil)
        
        
    }else{
        
        animations()
    }
    
}

代碼分析

//1

let userInfo  = note.userInfo as! NSDictionary

將通知的用戶信息取出,轉(zhuǎn)化為字典類型,里面所存的就是我們所需的信息:鍵盤動畫的時長、時間曲線;鍵盤的位置、高度信息。有了這些信息我們就可以do some magic了~
//2
通過對應(yīng)的鍵UIKeyboardFrameEndUserInfoKey,取出鍵盤位置信息
通過UIKeyboardAnimationDurationUserInfoKey,取出動畫時長信息
//3

var keyBoardBoundsRect = self.view.convertRect(keyBoardBounds, toView:nil)

由于取出的位置信息是絕對的,所以要將其轉(zhuǎn)換為對應(yīng)于當(dāng)前view的位置,否則位置信息會出錯!
//4

   var keyBaoardViewFrame = keyBaordView.frame
   var deltaY = keyBoardBounds.size.height

保存下輸入框的位置信息和y坐標(biāo)需要變換的量以便后面調(diào)用

//5

    let animations:(() -> Void) = {
        
        self.keyBaordView.transform = CGAffineTransformMakeTranslation(0,-deltaY)
    
    if duration > 0 {
        let options = UIViewAnimationOptions(UInt((userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).integerValue << 16))
        
        UIView.animateWithDuration(duration, delay: 0, options:options, animations: animations, completion: nil)
        
        
    }else{
        
        animations()
    }
    
}

首先使用仿射變換CGAffineTransformMakeTranslation,使輸入框的高度減少deltaY也就是跟隨鍵盤的位置向上移動;

此處難點在這里
 let options = UIViewAnimationOptions(UInt((userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).integerValue << 16))

這里是將時間曲線信息(一個64為的無符號整型)轉(zhuǎn)換為UIViewAnimationOptions類型,要通過左移16來完成類型轉(zhuǎn)換。

這個方法是在一個比較著名的解決bug的網(wǎng)站stackoverflow里找到的。

自我感覺這是比較坑的地方,它居然沒有用來進行類型轉(zhuǎn)換的方法,竟然還得要位!運!算!不過相信今后這個坑會被apple填上吧。。

然后呢就是把這些東西全部裝進UIView的動畫函數(shù)中,執(zhí)行動畫。

 UIView.animateWithDuration(duration, delay: 0, options:options, animations: animations, completion: nil)

這樣鍵盤彈出的方法就完全實現(xiàn)了!

接下來就是收回鍵盤的部分了:
這部分呢就比較簡單了,收回鍵盤時只需要動畫時長duration和時間曲線信息options所以只要留下他們就行了,然后再將輸入框的位置還原即可,這里有一個很巧妙的辦法

self.keyBaordView.transform = CGAffineTransformIdentity

這樣就可以還原所有變換~
下面是該方法的實現(xiàn):

func keyBoardWillHide(note:NSNotification)
{

    let userInfo  = note.userInfo as! NSDictionary
    
    let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    
    
    let animations:(() -> Void) = {
        
        self.keyBaordView.transform = CGAffineTransformIdentity
        
    }
    
    if duration > 0 {
        let options = UIViewAnimationOptions(UInt((userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).integerValue << 16))
        
        UIView.animateWithDuration(duration, delay: 0, options:options, animations: animations, completion: nil)
        
        
    }else{
        
        animations()
    }
          
}

實際上這個方法不會運行,因為并沒有判斷是否應(yīng)該收回鍵盤,我的解決方法是當(dāng)手指點擊輸入框之上的任何地方就會收回鍵盤,這個在我的完整demo會看到。

demo源代碼github

demo的效果:

鍵盤彈出demo.gif

如果本篇文章對你有幫助,可以點一下左下角的喜歡,大家的支持與鼓勵是繼續(xù)寫作的動力~(ps:這是我寫的第一篇文章)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容