解決自定義可拖動View在軟鍵盤彈出和隱藏時位置重置問題

GavinCui發表於2019-03-28

問題發生背景如下圖:

  • 需要實現一個可拖動且可點選的按鈕
  • 當拖動後按鈕的座標需要存到快取中,下次進入將按鈕設定到指定位置

解決自定義可拖動View在軟鍵盤彈出和隱藏時位置重置問題


於是心裡開始YY:"繼承View重寫onmeasur和onTouchEvent方法,測量window寬高,處理滑動事件*&…@……&&¥!……此處省略一萬字......"

解決自定義可拖動View在軟鍵盤彈出和隱藏時位置重置問題

so easy,直接開擼!

一頓操作猛如虎。。。

可拖動的view就不說了,沒啥可說的,主要是設定位置。最開始我用的是:

setX(x);setY(y);複製程式碼

然後滿懷欣喜的點選了Run....五分鐘以後....執行起來了..如圖?

解決自定義可拖動View在軟鍵盤彈出和隱藏時位置重置問題

按鈕的可活動頁面變成了紅線區域....

解決自定義可拖動View在軟鍵盤彈出和隱藏時位置重置問題

一頓操作猛如虎,發現自己二百五....問題出來了,那就解決唄。查閱嘗試之後發現layout()方法可以實現效果且不會偏移?

this.layout(mmkv.decodeInt("left"), mmkv.decodeInt("top")
               , mmkv.decodeInt("right"), mmkv.decodeInt("bottom"));複製程式碼

哎呀,終於搞定了,so easy~~~然而...當我點選輸入框的時候我才明白了什麼叫Too young,Too simple!!按鈕拖拽以後,點選輸入框,發現按鈕回到了初始位置,這就非常尷尬了。

以下是軟鍵盤的啟動方式:?

"stateUnspecified"

軟鍵盤的狀態(是否它是隱藏或可見)沒有被指定。系統將選擇一個合適的狀態或依賴於主題的設定。

這個是為了軟體盤行為預設的設定。

"stateUnchanged"

軟鍵盤被保持無論它上次是什麼狀態,是否可見或隱藏,當主視窗出現在前面時。

"stateHidden"

當使用者選擇該Activity時,軟鍵盤被隱藏——也就是,當使用者確定導航到該Activity時,而不是返回到它由於離開另一個Activity。

"stateAlwaysHidden"

軟鍵盤總是被隱藏的,當該Activity主視窗獲取焦點時。

"stateVisible"

軟鍵盤是可見的,當那個是正常合適的時(當使用者導航到Activity主視窗時)。

"stateAlwaysVisible"

當使用者選擇這個Activity時,軟鍵盤是可見的——也就是,也就是,當使用者確定導航到該Activity時,而不是返回到它由於離開另一個Activity。

"adjustUnspecified"

它不被指定是否該Activity主視窗調整大小以便留出軟鍵盤的空間,或是否視窗上的內容得到螢幕上當前的焦點是可見的。系統將自動選擇這些模式中一種主要依賴於是否視窗的內容有任何佈局檢視能夠滾動他們的內容。如果有這樣的一個檢視,這個視窗將調整大小,這樣的假設可以使滾動視窗的內容在一個較小的區域中可見的。這個是主視窗預設的行為設定。

"adjustResize"

該Activity主視窗總是被調整螢幕的大小以便留出軟鍵盤的空間

"adjustPan"

該Activity主視窗並不調整螢幕的大小以便留出軟鍵盤的空間。相反,當前視窗的內容將自動移動以便當前焦點從不被鍵盤覆蓋和使用者能總是看到輸入內容的部分。這個通常是不期望比調整大小,因為使用者可能關閉軟鍵盤以便獲得與被覆蓋內容的互動操作。

軟鍵盤彈起導致layout重新測量繪製,所以之前的layout()方法無效了,嘗試去在Manifest清單檔案中去更改啟動方式為 adjustNothing,Run之後發現:?

解決自定義可拖動View在軟鍵盤彈出和隱藏時位置重置問題

按鈕是在拖拽後的位置展示,但是!!我輸入框被遮擋了。。我輸入個東西還需要自備透視???解決自定義可拖動View在軟鍵盤彈出和隱藏時位置重置問題於是乎老老實實撤回了...這個方法不行,那就換個套路實現吧。既然每一次鍵盤彈出和收起,都對view進行了重新的測量和繪製,那麼就從這裡入手好了。首先,view的繪製有三個步驟,onMeasure()、onLayout()和onDraw(),onMeasure方法是對view進行測量,測量完成後onLayout開始對view進行佈局,最後onDraw方法開始繪製。那好,我在onDraw開始繪製view的時候,去對我的按鈕設定一個位置,就是我存在快取裡的位置,如下:?

/**
* 每次Draw時,重置view回到mmkv中儲存的位置 
* @param canvas 
*/
@Overrideprotected
 void onDraw(Canvas canvas) {   
 this.layout(mmkv.decodeInt("left"), mmkv.decodeInt("top")
            , mmkv.decodeInt("right"), mmkv.decodeInt("bottom"));
}複製程式碼

PS:這裡的快取使用的是Tencent 開源的MMKV框架

如此一來想要的結果基本就實現了,但是這種方法總覺得不是最佳解法,不知道大家還有其他辦法實現嗎?希望分享共同探討!


以上方法沒有在實際專案中用到,後面改了設計,當軟鍵盤彈出的時候在軟鍵盤之上加一個輸入框,軟鍵盤啟動方式設定為adjustNothing,出於好奇,就自己琢磨了這個解決方案,所以寫下來做一個記錄。如有不足之處,還希望指出共同學習進步!下面是程式碼的連結,如有需要可以點選?
github.com/GavinCui12/…




相關文章