Android鍵盤皮膚衝突 佈局閃動處理方案

發表於2016-03-30

起源,之前在微信工作的時候,為了給使用者帶來更好的基礎體驗,做了很多嘗試,踩了很多輸入法的坑,特別是動態調整鍵盤高度,二級頁面是透明背景,魅族早期的Smart bar等, 後來逐一完善了,考慮到擁抱開源,看業界還是有很多應用存在類似問題。就有了這個repo

之前有寫過一篇核心思想: Switching between the panel and the keyboard in Wechat

Android鍵盤皮膚衝突 佈局閃動處理方案Android鍵盤皮膚衝突 佈局閃動處理方案 Android鍵盤皮膚衝突 佈局閃動處理方案Android鍵盤皮膚衝突 佈局閃動處理方案

歡迎提交 Pull requests

  • 儘量多的英文註解。
  • 每個提交儘量的細而精準。
  • Commit message 遵循: AngularJS's commit message convention
  • 儘可能的遵循IDE的程式碼檢查建議(如 Android Studio 的 'Inspect Code')。

如何使用

build.gradle中引入:

compile 'cn.dreamtobe.kpswitch:library:1.4.4'

使用引導

非全屏主題情況下使用引導

所謂非全屏主題,就是 (activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0

Android鍵盤皮膚衝突 佈局閃動處理方案

I. AndroidManifest

可直接參照: AndroidManifest.xml

對應的Activity,在AndroidManifest中配置android:windowSoftInputMode=adjustResize

<manifest
  ...>
  <application
    ...>

    <activity
      android:name=".activity.ChattingActivity"
      android:windowSoftInputMode=adjustResize"/>
      ...
  </application>
  ...
</manifest>

II. 需要處理頁面的layout xml

可直接參照: activity_chatting_resolved.xml

  1. 需要用到 最上層佈局 (KPSwitchRootFrameLayout/KPSwitchRootLinearLayout/KPSwitchRootRelativeLayout)
  2. 需要用到 皮膚佈局(KPSwitchPanelFrameLayout/KPSwitchPanelLinearLayout/KPSwitchPanelRelativeLayout)。

簡單案例:

<?xml version="1.0" encoding="utf-8"?>
<!-- 可選用 KPSwitchRootLinearLayout、KPSwitchRootRelativeLayout、KPSwitchRootFrameLayout -->
<cn.dreamtobe.kpswitch.widget.KPSwitchRootLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- 佈局內容 -->
    ...

    <!-- 可選用 KPSwitchPanelLinearLayout、KPSwitchPanelRelativeLayout、KPSwitchPanelFrameLayout -->
    <cn.dreamtobe.kpswitch.widget.KPSwitchPanelLinearLayout
        android:id="@+id/panel_root"
        android:layout_width="fill_parent"
        android:layout_height="@dimen/panel_height"
        android:visibility="gone">
        <!-- 皮膚內容 -->
        ...
    </cn.dreamtobe.kpswitch.widget.KPSwitchPanelLinearLayout>

</cn.dreamtobe.kpswitch.widget.KPSwitchRootLinearLayout>

III. 需要處理頁面的Activity:

可直接參照: ChattingResolvedActivity.java

  1. 處理一些事件(KPSwitchConflictUtil)
  2. 鍵盤狀態(高度與顯示與否)監聽(KeyboardUtil#attach())

簡單案例:

...

// 皮膚View
private KPSwitchPanelLinearLayout mPanelLayout;
// 鍵盤焦點View,用於輸入內容
private EditText mSendEdt;
// 用於切換鍵盤與皮膚的按鈕View
private ImageView mPlusIv;

@Override
public void onCreate(Bundle saveInstanceState){
    ...

    mPanelLayout = (KPSwitchPanelLinearLayout)findViewById(R.id.panel_root);
    mSendEdt = (EditText) findViewById(R.id.send_edt);
    mPlusIv = (ImageView) findViewById(R.id.plus_iv);

    /**
     * 這個Util主要是監控鍵盤的狀態: 顯示與否 以及 鍵盤的高度
     * 這裡也有提供給外界監聽 鍵盤顯示/隱藏 的監聽器,具體參看
     * 這個介面 {@Link KeyboardUtil#attach(Activity, IPanelHeightTarget, OnKeyboardShowingListener)}
     */
    KeyboardUtil.attach(this, mPanelLayout);

    /**
     * 這個Util主要是協助處理一些皮膚與鍵盤相關的事件。
     * 這個方法主要是對一些相關事件進行註冊,如切換皮膚與鍵盤等,具體參看原始碼,比較簡單。
     * 裡面還提供了一些已經處理了衝突的工具方法: 顯示皮膚;顯示鍵盤;鍵盤皮膚切換;隱藏鍵盤與皮膚;
     *
     * @param panelRoot 皮膚的佈局。
     * @param switchPanelKeyboardBtn 用於觸發切換皮膚與鍵盤的按鈕。
     * @param focusView 鍵盤彈起時會給這個View focus,收回時這個View會失去focus,通常是傳送的EditText。
     */
    KPSwitchConflictUtil.attach(mPanelLayout, mPlusIv, mSendEdt);

}

...

...

// 如果需要處理返回收起皮膚的話
@Override
public boolean dispatchKeyEvent(KeyEvent event){
    if (event.getAction() == KeyEvent.ACTION_UP &&
            event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        if (mPanelLayout.getVisibility() == View.VISIBLE) {
            KPSwitchConflictUtil.hidePanelAndKeyboard(mPanelLayout);
            return true;
        }
    }
    return super.dispatchKeyEvent(event);
}

全屏主題情況下使用引導

所謂全屏主題,就是 (activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0

Android鍵盤皮膚衝突 佈局閃動處理方案

I. AndroidManifest

可直接參照: AndroidManifest.xml

對應的Activity,在 AndroidManifest中配置 android:windowSoftInputMode=adjustUnspecified,或者不配置,預設就是這個模式。

II. 需要處理頁面的layout xml

可直接參照: activity_chatting_fullscreen_resolved.xml

這邊只需要用到一個 皮膚佈局(KPSwitchFSPanelFrameLayout/KPSwitchFSPanelLinearLayout/KPSwitchFSPanelRelativeLayout)

<?xml version="1.0" encoding="utf-8"?>
...
    ...

    <!-- 可選用 KPSwitchFSPanelFrameLayout、KPSwitchFSPanelLinearLayout、KPSwitchFSPanelRelativeLayout -->
    <cn.dreamtobe.kpswitch.widget.KPSwitchFSPanelFrameLayout
        android:id="@+id/panel_root"
        style="@style/Panel"
        android:visibility="gone">

        ...
    </cn.dreamtobe.kpswitch.widget.KPSwitchFSPanelFrameLayout>

...

III. 需要處理頁面的Activity:

可直接參照: ChattingResolvedFullScreenActivity.java

  1. 主要是處理一些事件(KPSwitchConflictUtil)
  2. 鍵盤狀態(高度與顯示與否)監聽(KeyboardUtil#attach())
  3. onPause時,記錄鍵盤狀態用於從後臺回到當前佈局,恢復鍵盤狀態不至於衝突(IFSPanelConflictLayout#recordKeyboardStatus())

如下使用案例:

...

// 皮膚View
private KPSwitchFSPanelLinearLayout mPanelLayout;
// 鍵盤焦點View,用於輸入內容
private EditText mSendEdt;
// 用於切換鍵盤與皮膚的按鈕View
private ImageView mPlusIv;

@Override
public void onCreate(Bundle saveInstanceState){
    ...


    mPanelLayout = (KPSwitchFSPanelLinearLayout)findViewById(R.id.panel_root);
    mSendEdt = (EditText) findViewById(R.id.send_edt);
    mPlusIv = (ImageView) findViewById(R.id.plus_iv);

    /**
     * 這個Util主要是監控鍵盤的狀態: 顯示與否 以及 鍵盤的高度
     * 這裡也有提供給外界監聽 鍵盤顯示/隱藏 的監聽器,具體參看
     * 這個介面 {@Link KeyboardUtil#attach(Activity, IPanelHeightTarget, OnKeyboardShowingListener)}
     */
    KeyboardUtil.attach(this, mPanelLayout);

    /**
     * 這個Util主要是協助處理一些皮膚與鍵盤相關的事件。
     * 這個方法主要是對一些相關事件進行註冊,如切換皮膚與鍵盤等,具體參看原始碼,比較簡單。
     * 裡面還提供了一些已經處理了衝突的工具方法: 顯示皮膚;顯示鍵盤;鍵盤皮膚切換;隱藏鍵盤與皮膚;
     *
     * @param panelRoot 皮膚的佈局。
     * @param switchPanelKeyboardBtn 用於觸發切換皮膚與鍵盤的按鈕。
     * @param focusView 鍵盤彈起時會給這個View focus,收回時這個View會失去focus,通常是傳送的EditText。
     */
    KPSwitchConflictUtil.attach(mPanelLayout, mPlusIv, mSendEdt);

}

@Override
protected void onPause() {
  super.onPause();
  // 用於記錄當前的鍵盤狀態,在從後臺回到當前頁面的時候,鍵盤狀態能夠正確的恢復並且不會導致佈局衝突。
  mPanelLayout.recordKeyboardStatus(getWindow());
}

...

// 如果需要處理返回收起皮膚的話
@Override
public boolean dispatchKeyEvent(KeyEvent event){
    if (event.getAction() == KeyEvent.ACTION_UP &&
            event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        if (mPanelLayout.getVisibility() == View.VISIBLE) {
            KPSwitchConflictUtil.hidePanelAndKeyboard(mPanelLayout);
            return true;
        }
    }
    return super.dispatchKeyEvent(event);
}

基本原理

擴充套件閱讀

Android Studio 提示與技巧(官方文件翻譯)
Android中軟鍵盤彈出時關於佈局的問題 
android軟鍵盤彈出引起的各種不適終極解決方案
介紹 Visual Studio 的 Android 模擬器
JavaScript 資源大全中文版

為您推薦

hadoop分散式叢集搭建 
功能強大的驗證碼的Java類庫:Patchca
CAS實現SSO(單點登入)
Struts2 json plugin實戰2 
Webpack + React 開發之路

更多

Android
鍵盤
Android開發

專案描述:For resolve the layout conflict when keybord & panel are switching (Android鍵盤皮膚衝突 佈局閃動處理方案) — 檢視更多內容..

相關文章