Android解決登錄按鈕被鍵盤覆蓋的問題

一、基本介紹

市場上基本的應用都會有登錄,登錄作為一個灰常重要的頁面秤涩,給用戶的第一感覺一定要簡潔美觀,最關鍵還要體驗好(體驗不好嗽测,分分鐘都想卸載的沖動,哈哈哈...)肿孵,很多應用登錄按鈕被鍵盤覆蓋體驗就不是很好唠粥,還要把鍵盤收起來,再點擊按鈕登錄停做。下面主要針對按鈕被覆蓋的問題晤愧,解決方案就是當鍵盤彈出時,通過計算蛉腌,向上移動指定的高度官份,使按鈕不被鍵盤覆蓋。舉個栗子烙丛,簡書的App就是下圖這樣的舅巷,微信的登錄也類似。

簡書登錄頁面

二河咽、實現(xiàn)原理

首先判斷鍵盤是否能覆蓋住按鈕(或指定內(nèi)容)钠右,假設覆蓋了(覆蓋按鈕多少高度處理都是一樣的),通過獲取鍵盤的高度減去藍色箭頭的高度就是布局向上移動的距離忘蟹,這樣按鈕就不會被覆蓋飒房。注意:因為彈出鍵盤的同時搁凸,布局向上移動,所以需要監(jiān)聽鍵盤事件情屹。具體計算:

  • 向上移動距離 = 鍵盤高度 - 藍色箭頭高度
  • 鍵盤的高度:彈出鍵盤時坪仇,擠壓根布局多少就是鍵盤的高度,當然還有其它的方法垃你。
  • 藍色布局箭頭的高度:屏幕的高度減去Titlebar至登錄按鈕的高度(如果有底部虛擬返回鍵,需要減去虛擬高度喂很,如華為等手機)惜颇;也可以通過父布局減去子布局的高度,主要看你怎么布局少辣,方法有很多凌摄。
原理圖

三、具體代碼實現(xiàn)

  1. 布局文件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>
    
  2. 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);
                    }
                }
            });
        }
    }
    
  3. 用到的工具類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)效果圖:

效果圖

如有問題歡迎留言,感謝支持和關注。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末忙干,一起剝皮案震驚了整個濱河市器予,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捐迫,老刑警劉巖乾翔,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異施戴,居然都是意外死亡反浓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門赞哗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雷则,“玉大人,你說我怎么就攤上這事肪笋≡屡” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵涂乌,是天一觀的道長艺栈。 經(jīng)常有香客問我,道長湾盒,這世上最難降的妖魔是什么湿右? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮罚勾,結(jié)果婚禮上毅人,老公的妹妹穿的比我還像新娘吭狡。我一直安慰自己,他們只是感情好丈莺,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布划煮。 她就那樣靜靜地躺著,像睡著了一般缔俄。 火紅的嫁衣襯著肌膚如雪弛秋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天俐载,我揣著相機與錄音蟹略,去河邊找鬼。 笑死遏佣,一個胖子當著我的面吹牛挖炬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播状婶,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼意敛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了膛虫?” 一聲冷哼從身側(cè)響起草姻,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎走敌,沒想到半個月后碴倾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡掉丽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年跌榔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捶障。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡僧须,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出项炼,到底是詐尸還是另有隱情担平,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布锭部,位于F島的核電站暂论,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拌禾。R本人自食惡果不足惜取胎,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闻蛀,春花似錦匪傍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至薪棒,卻和暖如春手蝎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俐芯。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工柑船, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泼各。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像亏拉,于是被迫代替她去往敵國和親扣蜻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容