一、基本介紹
市場上基本的應用都會有登錄,登錄作為一個灰常重要的頁面秤涩,給用戶的第一感覺一定要簡潔美觀,最關鍵還要體驗好(體驗不好嗽测,分分鐘都想卸載的沖動,哈哈哈...)肿孵,很多應用登錄按鈕被鍵盤覆蓋體驗就不是很好唠粥,還要把鍵盤收起來,再點擊按鈕登錄停做。下面主要針對按鈕被覆蓋的問題晤愧,解決方案就是當鍵盤彈出時,通過計算蛉腌,向上移動指定的高度官份,使按鈕不被鍵盤覆蓋。舉個栗子烙丛,簡書的App就是下圖這樣的舅巷,微信的登錄也類似。
二河咽、實現(xiàn)原理
首先判斷鍵盤是否能覆蓋住按鈕(或指定內(nèi)容)钠右,假設覆蓋了(覆蓋按鈕多少高度處理都是一樣的),通過獲取鍵盤的高度減去藍色箭頭的高度就是布局向上移動的距離忘蟹,這樣按鈕就不會被覆蓋飒房。注意:因為彈出鍵盤的同時搁凸,布局向上移動,所以需要監(jiān)聽鍵盤事件情屹。具體計算:
- 向上移動距離 = 鍵盤高度 - 藍色箭頭高度
- 鍵盤的高度:彈出鍵盤時坪仇,擠壓根布局多少就是鍵盤的高度,當然還有其它的方法垃你。
- 藍色布局箭頭的高度:屏幕的高度減去Titlebar至登錄按鈕的高度(如果有底部虛擬返回鍵,需要減去虛擬高度喂很,如華為等手機)惜颇;也可以通過父布局減去子布局的高度,主要看你怎么布局少辣,方法有很多凌摄。
三、具體代碼實現(xiàn)
-
布局文件activity_login:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ll_login_root" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <RelativeLayout android:id="@+id/rel_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="16dp" android:paddingRight="16dp"> <ImageView android:id="@+id/img_login" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_margin="40dp" android:src="@mipmap/ic_launcher" /> <LinearLayout android:id="@+id/ll_account" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/img_login" android:layout_marginBottom="12dp" android:layout_marginTop="12dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="賬號 " android:textColor="@android:color/black" android:textSize="18sp" /> <EditText android:id="@+id/cet_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginRight="12dp" android:layout_weight="1" android:background="@null" android:hint="請輸入賬號" android:inputType="text" android:lines="1" android:textColorHint="#CCCCCC" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_below="@id/ll_account" android:background="#EAEAEA" /> <LinearLayout android:id="@+id/ll_code" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/ll_account" android:layout_marginBottom="12dp" android:layout_marginTop="12dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="密碼 " android:textColor="@android:color/black" android:textSize="18sp" /> <EditText android:id="@+id/et_pwd" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginRight="12dp" android:background="@null" android:hint="請輸入密碼" android:inputType="textPassword" android:lines="1" android:maxLength="16" android:textColorHint="#CCCCCC" /> </LinearLayout> <View android:id="@+id/line" android:layout_width="match_parent" android:layout_height="1dp" android:layout_below="@id/ll_code" android:background="#EAEAEA" /> <Button android:id="@+id/btn_login" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/line" android:layout_marginBottom="12dp" android:layout_marginTop="20dp" android:text="登錄" android:textSize="18sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/btn_login" android:layout_centerHorizontal="true" android:layout_marginBottom="12dp" android:text="忘記密碼" android:textSize="16sp" /> </RelativeLayout> </LinearLayout>
-
LoginActivity:
package com.chao.sample;import android.graphics.Rect; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.widget.LinearLayout; import android.widget.RelativeLayout; import butterknife.Bind; import butterknife.ButterKnife; /** * Created by Iven on 2016/12/25. */ public class LoginActivity extends AppCompatActivity { @Bind(R.id.rel_content) RelativeLayout relContent; @Bind(R.id.ll_login_root) LinearLayout llLoginRoot; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); ButterKnife.bind(this); keepLoginBtnNotOver(llLoginRoot, relContent); //觸摸外部漓帅,鍵盤消失 llLoginRoot.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Utils.closeKeyboard(LoginActivity.this); return false; } }); } /** * 保持登錄按鈕始終不會被覆蓋 * * @param root * @param subView */ private void keepLoginBtnNotOver(final View root, final View subView) { root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect rect = new Rect(); // 獲取root在窗體的可視區(qū)域 root.getWindowVisibleDisplayFrame(rect); // 獲取root在窗體的不可視區(qū)域高度(被其他View遮擋的區(qū)域高度) int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom; // 若不可視區(qū)域高度大于200锨亏,則鍵盤顯示,其實相當于鍵盤的高度 if (rootInvisibleHeight > 200) { // 顯示鍵盤時 int srollHeight = rootInvisibleHeight - (root.getHeight() - subView.getHeight()) - Utils.getNavigationBarHeight(root.getContext()); if (srollHeight > 0) {當鍵盤高度覆蓋按鈕時 root.scrollTo(0, srollHeight); } } else { // 隱藏鍵盤時 root.scrollTo(0, 0); } } }); } }
-
用到的工具類Utils:
package com.chao.sample; import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.util.Log; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import java.lang.reflect.Method; /** * Created by Iven on 2016/12/25. */ public class Utils { private static final String TAG = Utils.class.getSimpleName(); /** * 關閉鍵盤 * * @param activity */ public static void closeKeyboard(Activity activity) { if (activity.getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) { if (activity.getCurrentFocus() != null) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } } } /** * 判斷是否有虛擬底部按鈕 * * @return */ public static boolean checkDeviceHasNavigationBar(Context context) { boolean hasNavigationBar = false; Resources rs = context.getResources(); int id = rs.getIdentifier("config_showNavigationBar", "bool", "android"); if (id > 0) { hasNavigationBar = rs.getBoolean(id); } try { Class systemPropertiesClass = Class.forName("android.os.SystemProperties"); Method m = systemPropertiesClass.getMethod("get", String.class); String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys"); if ("1".equals(navBarOverride)) { hasNavigationBar = false; } else if ("0".equals(navBarOverride)) { hasNavigationBar = true; } } catch (Exception e) { Log.w(TAG, e); } return hasNavigationBar; } /** * 獲取底部虛擬按鍵高度 * * @return */ public static int getNavigationBarHeight(Context context) { int navigationBarHeight = 0; Resources rs = context.getResources(); int id = rs.getIdentifier("navigation_bar_height", "dimen", "android"); if (id > 0 && checkDeviceHasNavigationBar(context)) { navigationBarHeight = rs.getDimensionPixelSize(id); } return navigationBarHeight; } }
最后實現(xiàn)效果圖:
如有問題歡迎留言,感謝支持和關注。