登陸界面輸入用戶名或者密碼鍵盤擡起致使的遮蓋問題是個老問題了,網上有不少相似的解決方案。若是你剛好在登陸界面還有個頭像的話,如何優雅的處理這個頭像呢?目前最新版本的手機QQ的處理也是比較醉人——直接在下方留出一大片白,這樣子就避免了遮蓋的問題(「 」)。android
可是本人總以爲很差看,這裏本文將給出一個巧妙地處理頭像和遮蓋問題的例子。鍵盤隱藏和打開的效果圖以下:git
鍵盤彈出後總結起來主要是兩點:github
1. 輸入區域包括登陸按鈕總體上擡app
2. 原來的頭像縮小到右上角ide
總體上擡函數
作到這個很簡單,僅僅須要在AndroidManifest中對應的Activity的元素中加入windowSoftInputMode屬性:佈局
<activity android:name=".activity.LoginActivity" android:label="@string/login_button_text" android:launchMode="singleTask" android:windowSoftInputMode="stateHidden|stateUnchanged|adjustResize"/>
因而運行後跑起來發現登陸界面變成了這樣:post
這顯然不是咱們想要的,雖然總體上擡了,可是登陸按鈕卻依然被遮蓋。輸入完畢用戶名密碼後必需要先關閉輸入法才能點擊到登陸按鈕,等於多了一步操做。測試
那麼到這裏咱們就想到了是否能夠拿這個頭像作文章?能夠看到頭像佔據了很大的空間,那麼是否能夠在鍵盤擡起的時候咱們調整頭像的大小以及位置呢?答案是能夠得,可是首先咱們要作的是知道什麼時候鍵盤打開或者關閉,其次再來改變這個頭像。動畫
監控鍵盤的狀態
這個Activity的根佈局是一個RelativeLayout (文章最後會給出完整的佈局):
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/login_root" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/shape_login_bg_start"> ... </RelativeLayout>
因爲上面鍵盤擡起的時候那個checkbox依然能夠點擊到,因此咱們這裏作個測試,鍵盤分別是關閉和打開的時候,點擊checkbox來計算下這個根佈局RelativeLayout的高度是否在變化,添加的測試代碼爲:
@Bind(R.id.login_root) RelativeLayout mRoot; 。。。 pwdCheck.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { L.d("root view height : " + mRoot.getHeight()); } });
依次在鍵盤隱藏和擡起的時候點擊checkbox來查看下log:
11-25 14:27:28.710 5623-5623/com.qianmi.shine D/shine: root view height : 1860 11-25 14:27:31.240 5623-5623/com.qianmi.shine D/shine: root view height : 1033
發現這個RelativeLayout的高度在鍵盤隱藏和擡起的時候是在變化的,那麼它的onSideChange這個函數確定是一直在被調用的。因此咱們能夠本身繼承一個RelativeLayout,同時複寫它的onSizeChange函數,經過高度的變化來判斷鍵盤是否打開,同時暴露出一個接口給Activity實現,讓Activity在該接口中根據鍵盤的狀態來改變頭像的佈局。這個自定義的繼承自RelativeLayout的控件以下:
public class ResizeRelativeLayout extends RelativeLayout { public static final int HIDE = 0; public static final int SHOW = 1; private Handler mainHandler = new Handler(); public ResizeRelativeLayout(Context context) { super(context); // TODO Auto-generated constructor stub } public ResizeRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override protected void onSizeChanged(int w,final int h, int oldw,final int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); mainHandler.post(new Runnable() { @Override public void run() { if (oldh - h > 50){ keyBordStateListener.onStateChange(SHOW); } else { if(keyBordStateListener != null){ keyBordStateListener.onStateChange(HIDE); } } } }); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub super.onLayout(changed, l, t, r, b); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); } private KeyBordStateListener keyBordStateListener; public void setKeyBordStateListener(KeyBordStateListener keyBordStateListener) { this.keyBordStateListener = keyBordStateListener; } public interface KeyBordStateListener{ public void onStateChange(int state); } }
在onSizeChange中判斷當前的height若是大於過去的height,即說明鍵盤是隱藏了;反之就是顯示了。
Activity對應的修改以下:
@Bind(R.id.login_root) ResizeRelativeLayout mRoot; @Override public void onStateChange(int state) { switch (state) { case ResizeRelativeLayout.HIDE: //TODO when keyboard is hide break; case ResizeRelativeLayout.SHOW: //TODO when keyboard is show break; } } mRoot.setKeyBordStateListener(this);
頭像的變化
有了鍵盤狀態的監聽後,頭像變化的處理就變的隨性了。爲了簡單起見,這裏咱們在根佈局的右上角一樣放置了一個ImageView,他和原來的頭像ImageView顯示一樣的內容。當鍵盤彈起的時候顯示右上角的頭像而隱藏中間的大頭像(注意必定要設置爲Gone,這樣子的話佈局在onMeasure的時候纔會把原來屬於大頭像的空間騰出來從而讓下方的輸入框和登陸按鈕向上擡起的更多);當鍵盤隱藏的時候則顯示中間大頭像而隱藏右上角的頭像。
修改onStateChange爲:
@Bind(R.id.card_small) CardView cardSmall; @Bind(R.id.card) CardView card; @Override public void onStateChange(int state) { switch (state) { case ResizeRelativeLayout.HIDE: card.setVisibility(View.VISIBLE); cardSmall.setVisibility(View.INVISIBLE); break; case ResizeRelativeLayout.SHOW: card.setVisibility(View.GONE); cardSmall.setVisibility(View.VISIBLE); break; } }
(這裏須要註明的是,爲了讓ImageView帶陰影,特地用了一個CardView來包含ImageView,由於CardView自帶陰影效果,因此這裏即對CardView進行可見性變化,具體見文末的佈局完整文件;其次這裏爲了作出帶圓角的ImageView,用了別的人一個控件,RoundedImageView,請參考https://github.com/vinc3m1/RoundedImageView)
若是須要作的帶感的話,能夠對中間的大頭像作以下的屬性動畫(必定要是屬性動畫,由於這樣才能真正的「移動」而騰出空間)而不用顯示另外一個右上角的小頭像:
1. ImageView經過scaleX和scaleY來縮小size
2. ImageView經過translateX和translateY來移動到右上角
附完整的佈局文件:
<?xml version="1.0" encoding="utf-8"?> <com.qianmi.shine.widget.ResizeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/login_root" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/shape_login_bg_start"> <android.support.v7.widget.CardView android:id="@+id/card_small" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:layout_margin="20dp" android:visibility="invisible" app:cardBackgroundColor="@color/transparent" app:cardCornerRadius="2dp" app:cardElevation="2dp"> <com.makeramen.roundedimageview.RoundedImageView android:id="@+id/profile_small" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/login_btn_photo_l" android:scaleType="fitCenter" android:src="@drawable/photo_l" app:riv_corner_radius="2dp" /> </android.support.v7.widget.CardView> <LinearLayout android:layout_width="315dp" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:orientation="vertical"> <android.support.v7.widget.CardView android:id="@+id/card" android:layout_width="98dp" android:layout_height="98dp" android:layout_gravity="center_horizontal" android:layout_marginBottom="@dimen/login_input_height" app:cardBackgroundColor="@color/transparent" app:cardCornerRadius="2dp" app:cardElevation="2dp"> <com.makeramen.roundedimageview.RoundedImageView android:id="@+id/profile" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/login_btn_photo_l" android:scaleType="fitCenter" android:src="@drawable/photo_l" app:riv_corner_radius="2dp" /> </android.support.v7.widget.CardView> <EditText android:id="@+id/et_login_username" android:layout_width="match_parent" android:layout_height="@dimen/login_input_height" android:layout_marginLeft="@dimen/login_margin_left" android:background="@drawable/shape_solid_transparent" android:drawableLeft="@drawable/login_icon_company" android:drawablePadding="@dimen/login_padding" android:hint="@string/login_input_hint_username" android:inputType="textPersonName" android:singleLine="true" android:textColor="@color/ColorPrimary" android:textColorHint="@color/text_hint_color" android:textCursorDrawable="@drawable/common_input_cursor" android:textSize="@dimen/login_input_text_size" /> <TextView android:id="@+id/line1" style="@style/common_login_horizontalLine_matchParent_normal" /> <EditText android:id="@+id/et_login_employ_name" android:layout_width="match_parent" android:layout_height="@dimen/login_input_height" android:layout_marginLeft="@dimen/login_margin_left" android:background="@drawable/shape_solid_transparent" android:drawableLeft="@drawable/login_icon_man" android:drawablePadding="@dimen/login_padding" android:hint="@string/login_input_hint_employ" android:inputType="textPersonName" android:singleLine="true" android:textColor="@color/ColorPrimary" android:textColorHint="@color/text_hint_color" android:textCursorDrawable="@drawable/common_input_cursor" android:textSize="@dimen/login_input_text_size" /> <TextView android:id="@+id/line2" style="@style/common_login_horizontalLine_matchParent_normal" /> <EditText android:id="@+id/et_login_pwd" android:layout_width="match_parent" android:layout_height="@dimen/login_input_height" android:layout_marginLeft="@dimen/login_margin_left" android:background="@drawable/shape_solid_transparent" android:drawableLeft="@drawable/login_icon_lock" android:drawablePadding="@dimen/login_padding" android:hint="@string/login_input_hint_pwd" android:inputType="textPassword" android:singleLine="true" android:textColor="@color/ColorPrimary" android:textColorHint="@color/text_hint_color" android:textCursorDrawable="@drawable/common_input_cursor" android:textSize="@dimen/login_input_text_size" /> <TextView android:id="@+id/line3" style="@style/common_login_horizontalLine_matchParent_normal" /> <CheckBox android:id="@+id/remember_pwd" style="@style/RememberPasswordCheckBox" android:layout_marginLeft="@dimen/login_margin_left" android:text="@string/login_remember_pwd" /> <Button android:id="@+id/btn_login" android:layout_width="match_parent" android:layout_height="46dp" android:layout_gravity="center_horizontal" android:layout_marginTop="32dp" android:background="@drawable/common_green_btn_selector" android:focusable="true" android:text="@string/login_button_text" android:textColor="@color/text_button_login" android:textSize="@dimen/login_btn_text_size" /> </LinearLayout> </com.qianmi.shine.widget.ResizeRelativeLayout>