Android 模仿QQ登錄界面解決軟鍵盤遮擋問題

Android 軟件盤彈出可能會遮擋住界面上的某些控件猖凛。當(dāng) windowSoftInputMode 為 adjustPan 時舀锨,一般不會擋住 EditText大审,但是假如 EditText 下面是一個登錄按鈕,那么這個按鈕就可能被擋住许布,但有時我們希望用戶輸完密碼可以直接點擊登錄按鈕替废,而不用把軟鍵盤收起來箍铭。這時就需要用到 adjustResize,這種模式能夠獲取到軟鍵盤的高度椎镣,這樣我們就能夠精確的對界面進(jìn)行控制诈火。

在閱讀本章之前,你應(yīng)該了解 windowSoftInputMode 的一些屬性状答,特別是 adjustResize柄瑰,如果還不熟悉,建議先閱讀Android 軟鍵盤之 windowSoftInputMode 分析再回過頭來繼續(xù)往下看剪况。

QQ 登錄界面很好的解決了軟鍵盤遮擋問題,當(dāng)然在大屏手機(jī)上軟鍵盤并不會擋住登錄按鈕蒲跨。今天我們也來模仿一個 QQ 登錄界面译断,最終效果如下:


QQ登錄界面

監(jiān)聽軟鍵盤彈出及收起事件

step1. 指定 windowSoftInputMode="adjustResize"

在 AndroidManifest.xml 中相應(yīng)的 Activity 設(shè)置 android:windowSoftInputMode="adjustResize",也可以在 java 代碼中設(shè)置或悲。

step2. 監(jiān)聽 contentView 寬高(layout) 變化

獲取 ViewTreeObserver 并監(jiān)聽 OnGlobalLayoutListener, 當(dāng)viewTree的布局發(fā)生變化時onGlobalLayout將會回調(diào)孙咪。我們新建一個KeyboardHelper輔助類。

KeyboardHelper.java

public class KeyboardHelper {
    private Activity activity;
    private OnKeyboardStatusChangeListener onKeyboardStatusChangeListener;
    private int windowBottom = -1;
    private int keyboardHeight = 0;

    public KeyboardHelper(Activity activity) {
        this.activity = activity;
        activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        if (activity.getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }

    public void onCreate() {
        View content = activity.findViewById(android.R.id.content);
        // content.addOnLayoutChangeListener(listener); 這個方法有時會出現(xiàn)一些問題
        content.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
    }

    public void onDestroy() {
        View content = activity.findViewById(android.R.id.content);
        ViewUtils.removeOnGlobalLayoutListener(content, onGlobalLayoutListener);
    }

    private OnGlobalLayoutListener onGlobalLayoutListener = new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Rect rect = new Rect();
            activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
            Log.d("KeyboardHelper", "onGlobalLayout: " + rect + ", " + windowBottom);
            int newBottom = rect.bottom;
            if (windowBottom != -1 && windowBottom != newBottom) {
                if (newBottom < windowBottom) {
                    // keyboard pop
                    keyboardHeight = windowBottom - newBottom;
                    if (onKeyboardStatusChangeListener != null) {
                        onKeyboardStatusChangeListener.onKeyboardPop(keyboardHeight);
                    }
                } else {
                    // keyboard close
                    if (onKeyboardStatusChangeListener != null) {
                        onKeyboardStatusChangeListener.onKeyboardClose(keyboardHeight);
                    }
                }
            }
            windowBottom = newBottom;
        }
    };

    public void setOnKeyboardStatusChangeListener(
            OnKeyboardStatusChangeListener onKeyboardStatusChangeListener) {
        this.onKeyboardStatusChangeListener = onKeyboardStatusChangeListener;
    }
    
    public interface OnKeyboardStatusChangeListener {

        void onKeyboardPop(int keyboardHeight);

        void onKeyboardClose(int keyboardHeight);
    }
}

ViewUtils.java


public class ViewUtils {

    public static void removeOnGlobalLayoutListener(View view, ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener) {
        if (Build.VERSION.SDK_INT < 16) {
            view.getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayoutListener);
        } else {
            view.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
        }
    }

}

代碼比較簡單巡语,無非是獲取window的可視坐標(biāo)翎蹈,通過比較bottom的值來判斷軟鍵盤是彈出還是收起。

實現(xiàn) QQ 登錄界面

有了這個 KeyBoardHelper男公,那么要實現(xiàn)和 QQ 登錄界面一樣的效果就不難了荤堪。我們甚至不需要任何自定義控件。思路是在軟鍵盤彈出時,把登錄按鈕以上的布局往上移澄阳,只要為其設(shè)置一個負(fù)值的 topMargin 即可拥知。

如圖所示:


QQ登錄界面示意圖

MainActivity 代碼如下:


public class MainActivity extends Activity {

    private int bottomHeight;
    private KeyboardHelper keyboardHelper;
    private View layoutBottom;
    private View layoutContent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qq_login);

        layoutContent = findViewById(R.id.layout_content);
        layoutBottom = findViewById(R.id.layout_bottom);
        keyboardHelper = new KeyboardHelper(this);
        keyboardHelper.onCreate();
        keyboardHelper.setOnKeyboardStatusChangeListener(onKeyBoardStatusChangeListener);
        layoutBottom.post(new Runnable() {
            @Override
            public void run() {
                bottomHeight = layoutBottom.getHeight();
            }
        });
    }

    private OnKeyboardStatusChangeListener onKeyBoardStatusChangeListener = new OnKeyboardStatusChangeListener() {

        @Override
        public void onKeyboardPop(int keyboardHeight) {

            final int height = keyboardHeight;
            if (bottomHeight > height) {
                layoutBottom.setVisibility(View.GONE);
            } else {
                int offset = bottomHeight - height;
                final ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) layoutContent
                        .getLayoutParams();
                lp.topMargin = offset;
                layoutContent.setLayoutParams(lp);
            }

        }

        @Override
        public void onKeyboardClose(int keyboardHeight) {
            if (View.VISIBLE != layoutBottom.getVisibility()) {
                layoutBottom.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        layoutBottom.setVisibility(View.VISIBLE);
                    }
                }, 300);
            }
            final ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) layoutContent
                    .getLayoutParams();
            if (lp.topMargin != 0) {
                lp.topMargin = 0;
                layoutContent.setLayoutParams(lp);
            }

        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        keyboardHelper.onDestroy();
    }
}

布局文件:activity_qq_login.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/layout_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="50dp">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="18dp"
            android:contentDescription="marginTop68dp"
            android:scaleType="centerInside"
            android:src="@drawable/qq_ava"
            android:visibility="visible" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="18dp"
            android:background="#f3f0f0"
            android:paddingBottom="100dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="100dp"
            android:text="這里為了演示增加一個TextView使登陸按鈕在鍵盤底部"
            android:textColor="#333333"
            android:textSize="13sp" />

        <LinearLayout
            android:id="@+id/layout_ed"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ffffff"
            android:divider="@drawable/divider"
            android:orientation="vertical"
            android:showDividers="middle">

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@null"
                android:hint="QQ號/手機(jī)號/郵箱"
                android:padding="10dp"
                android:textColor="#000000"
                android:textColorHint="#d2d2d2"
                android:textCursorDrawable="@null" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@null"
                android:hint="密碼"
                android:padding="10dp"
                android:textColor="#000000"
                android:textColorHint="#d2d2d2"
                android:textCursorDrawable="@null" />
        </LinearLayout>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="14dp"
            android:layout_marginRight="14dp"
            android:layout_marginTop="14dp"
            android:background="@drawable/btn_login"
            android:text="登陸"
            android:textSize="17sp" />

        <RelativeLayout
            android:id="@+id/layout_bottom"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/tv_cannot_login"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_margin="14dp"
                android:text="無法登陸?"
                android:textColor="@color/action_bar_bg"
                android:textSize="14sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:layout_margin="14dp"
                android:text="新用戶"
                android:textColor="@color/action_bar_bg"
                android:textSize="14sp" />
        </RelativeLayout>
    </LinearLayout>

    <include
        android:id="@+id/appbar"
        layout="@layout/appbar"
        android:layout_width="match_parent"
        android:layout_height="50dp" />

</FrameLayout>

點我下載源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碎赢,一起剝皮案震驚了整個濱河市低剔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肮塞,老刑警劉巖襟齿,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異枕赵,居然都是意外死亡猜欺,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門烁设,熙熙樓的掌柜王于貴愁眉苦臉地迎上來替梨,“玉大人,你說我怎么就攤上這事装黑「逼伲” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵恋谭,是天一觀的道長糠睡。 經(jīng)常有香客問我,道長疚颊,這世上最難降的妖魔是什么狈孔? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮材义,結(jié)果婚禮上均抽,老公的妹妹穿的比我還像新娘。我一直安慰自己其掂,他們只是感情好油挥,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著款熬,像睡著了一般深寥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贤牛,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天惋鹅,我揣著相機(jī)與錄音,去河邊找鬼殉簸。 笑死闰集,一個胖子當(dāng)著我的面吹牛沽讹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播返十,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼妥泉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了洞坑?” 一聲冷哼從身側(cè)響起盲链,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎迟杂,沒想到半個月后刽沾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡排拷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年侧漓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片监氢。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡布蔗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浪腐,到底是詐尸還是另有隱情纵揍,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布议街,位于F島的核電站泽谨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏特漩。R本人自食惡果不足惜吧雹,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涂身。 院中可真熱鬧雄卷,春花似錦、人聲如沸蛤售。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悍抑。三九已至,卻和暖如春杜耙,著一層夾襖步出監(jiān)牢的瞬間搜骡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工佑女, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留记靡,地道東北人谈竿。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像摸吠,于是被迫代替她去往敵國和親空凸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

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