前言
有輸入框的地方
就有軟鍵盤
那是一種洪鸭,會呼吸的痛
第一個故事
留言板
錯誤的打開方式
仔細觀察會發(fā)現间影,當軟鍵盤彈出時 background膛锭、recyclerview搀罢、toolbar 被軟鍵盤頂上去了腋粥!這樣的交互簡直不能忍晦雨,對用戶來說也非常突兀架曹。
正確的打開方式
軟鍵盤彈出只是遮蓋了 background 一部分,background 沒有被壓縮闹瞧。
實現
1. AndroidMainifest.xml 配置文件
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize">
2. activity_main.xml 布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 關鍵處绑雄,用 ScrollView 包裹 ImageView -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@mipmap/bg_leave_msg_board" />
</ScrollView>
<!-- Toolbar-->
<include layout="@layout/view_msg_board_app_bar_layout" />
<!-- Recyclerview-->
<geeklub.org.hellovass.endless_recyclerview.widget.HVEndlessRecyclerView
android:id="@+id/rv_msg_board"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<!-- 輸入框-->
<geeklub.org.messageboarddemo.widget.LeaveMessageBoard
android:id="@+id/leave_msg_board"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@android:color/white"
app:layout_behavior="geeklub.org.messageboarddemo.LeaveMessageViewBehavior" />
</android.support.design.widget.CoordinatorLayout>
目瞪口呆,為什么這樣搞定了奥邮?
android:windowSoftInputMode 屬性
Value | Description |
---|---|
adjustPan | 軟鍵盤彈出時万牺,Activity 主窗口不會調整大小留出空間給軟鍵盤。相反洽腺,window 的內容將自動移動以便當前焦點不被鍵盤覆蓋(用戶總是能看到輸入內容的部分) |
adjustResize | 軟鍵盤彈出時脚粟,對 Activity 主窗口調整大小以留出軟鍵盤的空間 |
很明顯,錯誤的姿勢.gif 中使用的是第一種屬性蘸朋。
android:windowSoftInputMode = adjustResize 時, Activity 究竟做了什么?
簡單自定義 ImageView核无、ScrollView,打印出關鍵信息
public class HVImageView extends ImageView {
private static final String TAG = HVImageView.class.getSimpleName();
// 省略部分代碼...
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.i(TAG, "onMeasure,height -->" + MeasureSpec.getSize(heightMeasureSpec));
}
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
Log.i(TAG, "onLayout,left -->" + l + ",top -->>" + t + ", right -->>" + r + ",bottom -->>" + b);
}
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.i(TAG, "onSizeChanged,width -->"
+ w
+ ",height -->>"
+ h
+ ", oldWidth -->>"
+ oldw
+ ",oldHeight -->>"
+ oldh);
}
}
// 省略自定義 HVScrollView 代碼
bg_leave_msg_board.jpg
HVImageView 的 log 信息
第一次啟動時
軟鍵盤彈出時
軟鍵盤隱藏時
從 log 中可以看出度液,從第一次啟動后 ImageView 的onSizeChanged
就不再執(zhí)行厕宗。軟鍵盤無論隱藏或彈出,bottom 的值一直是 2130px堕担。
HVScrollView 的 log 信息
第一次啟動時
鍵盤彈出時
鍵盤隱藏時
從 log 中可以看出已慢,ScrollView 的 onSizeChanged
是一直會被調用的。鍵盤彈出時霹购,height:1776px->1072px; 鍵盤隱藏時佑惠,height:1072px ->1776px。
分析
思路
ImageView 的長寬比應該與背景圖的長寬比(1080px / 1917px = 0.5634)相同齐疙。背景圖需要完整顯示在 ImageView膜楷,并且占滿 ImageView。
windowSoftInputMode
設置為adjustResize
贞奋, Activity 主窗口調整大小時 ImageView 的 height 需要保持不變赌厅。
利用 adjustViewBounds 屬性解決第一個問題
設置為 true 的時候調整 ImageView 的邊界來保持 drawable 的長寬比。
此時轿塔,ImageView 的 height = 屏幕的寬度(1200px) / 圖片長寬比(0.56) = 2130px特愿。
使用 ScrollView 包裹 ImageView 解決第二個問題
ScrollView 的 onSizeChanged 方法會在軟鍵盤彈出、隱藏時被調用勾缭,而 ImageView 的 onSizeChanged 不會被調用揍障,height 也就不會變化了。
軟鍵盤彈出時俩由,ScrollView 高度減小毒嫡,ImageView 的高度不變(這點很重要),我們能看到的背景圖區(qū)域就縮小了幻梯,背景圖被軟鍵盤覆蓋兜畸。
同理努释,軟鍵盤隱藏時也一樣。
到這里膳叨,疑問也差不多解答完了...
補充得到軟鍵盤高度的幾種方法
其實這個問題和背景圖被壓縮并沒有一毛錢關系洽洁,但是,如果要做到 QQ 聊天頁面相近的體驗——鍵盤彈出時菲嘴,將 recyclerview/listview 滾動對應的距離(鍵盤的高度),這時候汰翠,如果能 SDK 里直接提供了這樣的方法該多好啊龄坪。然而,并沒有复唤!
方法一
/**
* 得到虛擬按鍵的高度
*
* @return 虛擬按鍵的高度
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public static int getSupportNavigationBarHeight(
Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// 獲取可用的高度
DisplayMetrics defaultDisplayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(defaultDisplayMetrics);
int usableHeight = defaultDisplayMetrics.heightPixels;
// 獲取實際的高度
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getRealMetrics(realDisplayMetrics);
int realHeight = realDisplayMetrics.heightPixels;
return realHeight > usableHeight ? realHeight - usableHeight : 0;
}
/**
* 得到當前軟鍵盤的高度
*
* @return 軟鍵盤的高度
*/
public static int getSoftInputHeight(Activity activity) {
Rect rect = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int screenHeight = activity.getWindow().getDecorView().getRootView().getHeight();
int softInputHeight = screenHeight - rect.bottom;
// Android LOLLIPOP 以上的版本才有虛擬按鍵
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
softInputHeight -= getSupportNavigationBarHeight(activity);
}
return softInputHeight;
}