EditText導致的問題
在使用EditText
並且將其放在屏幕底部的時候,往往會使用例如:
android:windowSoftInputMode="adjustResize|stateHidden"
- 1
- 1
等這樣的參數,但是它有着很大的缺點,會導致界面上移、EditText
被擋住的問題一些問題。
簡單思考EditText鍵盤彈出後爲什麼導致界面上移呢?
不從代碼層次上考慮,當鍵盤彈出後,鍵盤本身佔據一定空間會致使EditText
隨之上移,EditText
上移也會導致同一佈局層次的其他控件發生位移狀況,這就是我們常常碰到的情況,也是非常頭痛。
那麼,如果將EditText
放在一個獨立層次的控件中,並且讓其上部(因爲往往EditText
都會放在底部)有一個自動控制其大小寬高的控件,是不是就會解決這個問題呢?
答案是肯定的!
將EditText放入獨立的層次佈局中,並輔以可自動收縮的控件。
類似於這樣:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/send_edt"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_alignParentBottom="true"
android:gravity="center_vertical|left"
android:imeOptions="actionSend|flagNoExtractUi"
android:lines="1"
android:minHeight="38dp"
android:padding="5dp"
android:textColor="#222222"
android:textColorHint="#b4b4b4"
android:textSize="13sp"
android:visibility="visible" />
<!--也可以是RecyclerView或ListView,但是不能是LinearLayout或RelativeLayout等佈局-->
<ScrollView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_above="@id/send_edt" />
</RelativeLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
你可以直接將這段代碼放入到你的Demo中,就會驚人的發現EditText
會如你所願的彈出。
但是問題真正結束了麼?當然沒有。
在全屏化的體驗中,我們的背景往往是一個VideoView
或SurfaceView
等類似的播放控件。
如果僅僅按照我們如上所示的做,你會發現VideoView
或SurfaceView
這樣的控件,在播放時播放內容會被自動縮小,這也是我們不可接受的。
此時,我的佈局如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context="com.bzh.FullscreenActivity">
<!-- The primary full-screen view. This can be replaced with whatever view
is needed to present your content, e.g. VideoView, SurfaceView,
TextureView, etc. -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#CCFF00FF"
android:padding="30dp">
<VideoView
android:layout_centerInParent="true"
android:id="@+id/fullscreen_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#55ff00ff"
/>
</RelativeLayout>
<!-- This FrameLayout insets its children based on system windows using
android:fitsSystemWindows. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/send_edt"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_alignParentBottom="true"
android:gravity="center_vertical|left"
android:imeOptions="actionSend|flagNoExtractUi"
android:lines="1"
android:minHeight="38dp"
android:padding="5dp"
android:textColor="#222222"
android:textColorHint="#b4b4b4"
android:textSize="13sp"
android:visibility="visible" />
<!--也可以是RecyclerView或ListView,但是不能是LinearLayout或RelativeLayout等佈局-->
<ScrollView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_above="@id/send_edt" />
</RelativeLayout>
</FrameLayout>
</FrameLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
那麼如何解決這個問題? 我在Google的全屏化Demo中找到了靈感。
藉助View.setSystemUiVisibility()
方法來達到真正的全屏化目的
很多同學查閱Android如何全屏化的時候,往往都會得到如下的結果:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- 1
- 1
使用Window
的flag來達到目的,但是千萬不要這麼作,如果你的全屏化狀態帶有和用戶交互的行爲,你就應該選擇另一種全屏化代碼:
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- 1
- 1
具體詳細的例子可以看Google的官方例子:
AndroidStudio -> NewProject -> 項目名 -> 選擇模板(FullScreen)
- 1
- 1
當我們加上如上代碼時鍵盤彈出就不會導致VideoView
控件播放內容被擠壓了。
但是,問題還沒有結束,你會發現EditText
的輸入框不見了。
Why?這是因爲EditText
並沒有隨着View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
生效後自動調整。
這個問題的解決辦法Google的FullScreen例子也給出瞭解決辦法,加入android:fitsSystemWindows.
:
<!-- This FrameLayout insets its children based on system windows using
android:fitsSystemWindows. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
至此,EditText
所引發的問題就得到解決了。
Demo地址 [https://github.com/biezhihua/FullScreenDemo]
View.setSystemUiVisibility介紹
public void setSystemUiVisibility(int visibility)
- 1
- 1
達到交互式全屏化是調用了上述方法,並通過改變參數來達到隱藏和顯示狀態欄的目的,其方法簡介如下:
- 改變狀態欄或者屏幕其他系統UI的可見性。
- 允許你App的內容放置在系統操作欄(狀態欄)之下,通過平滑的過度效果來隱藏和顯示系統UI。
- 使用這個方法讓用戶集中更多的注意力在你應用的內容上。
- 典型的使用到這個方法的場景是:雜誌閱讀器/視頻播放器
總結來說,如果你做的是視頻播放器,使用這個方法來達到全屏化的目的,比單純調用下面的方法來達到全屏化,得到的交互效果會更加流暢和絲滑。
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- 1
- 1
Flags參數到底是什麼意思?
接下來,我們就挨個看看這些常量都是什麼意思。
View.SYSTEM_UI_FLAG_LOW_PROFILE
View.SYSTEM_UI_FLAG_FULLSCREEN
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
View.SYSTEM_UI_FLAG_LOW_PROFILE
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
請求系統UI進入一個“低調”的模式。在遊戲,閱讀器,視頻播放器等需要“沉浸式”體驗的應用中,系統UI常常會讓用戶分心。在這種模式下,狀態欄和導航欄會變暗。
View.SYSTEM_UI_FLAG_FULLSCREEN
- 1
- 1
請求進入全屏模式,但同時仍然允許用戶與系統UI進行交互,這與WindowManager.LayoutParams.FLAG_FULLSCREEN具有相同的視覺效果,一些非關鍵畫面UI(如狀態欄)將被隱藏。
但是,WindowManager.LayoutParams.FLAG_FULLSCREEN更強調讓用戶一直處於一個連續的狀態,比如玩遊戲。而這個標記則更強調一種沉浸狀態,用戶可以迅速的退出這種狀態。
舉個例子,我們看小說的時候,很多時間會專心與小說本身,但是當用戶想看一下時間時,點擊屏幕,我們可以迅速友好顯示系統UI和一些操作控制UI。
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- 1
- 1
簡單來說,就是防止隱藏和顯示系統UI時,控件發生抖動。
如果加上這個設置,無論怎麼顯示和隱藏系統UI,我們都回到得到一個平滑的過渡效果。
假如你設置了WindowManager.FLAG_FULLSCREEN標記而不是View.SYSTEM_UI_FLAG_FULLSCREE,那麼你將得到一直處於隱藏狀態的狀態欄。
注意,改變或清除WindowManager.FLAG_FULLSCREEN不會得到一個平滑的過渡效果。
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- 1
- 1
效果是增強顯示和隱藏系統UI時的交互體驗。
如果不設置的話,那麼任何與系統UI的交互,都會導致退出全屏狀態。如果設置的話,那麼系統UI會短暫的覆蓋應用的內容,而且還有一定程度的透明度,並且短暫時間後自動隱藏,並不會退出全屏化。
看一下效果圖會更明顯一些。
這是全屏化狀態
這是設置後的效果。
這是未設置的效果,與系統UI交互直接退出全屏狀態。
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- 1
- 1
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- 1
- 1
如果窗口有被設置爲SYSTEM_UI_FLAG_FULLSCREEN的需求,那麼請設置這兩個標記,這樣可以避免切換系統UI顯示與隱藏時,AppUI被覆蓋。
如果不設置就會出現下面的情況。
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- 1
- 1
隱藏導航欄
以上都是被全屏化的View所需要進行的處理。對於控制器來說,如果不在佈局中設置android:fitsSystemWindows=true
屬性,那麼控制器的UI就會跑到狀態欄的下面。
爲了避免以上的情況,就不得不解釋
setFitsSystemWindows(boolean)
和fitSystemWindows(rect)
方法了。
setFitsSystemWindows()
方法是設置此視圖是否應該考慮系統UI,例如狀態欄。併爲其留出空間。如果參數爲true,代表會爲系統UI留出空間,那麼fitSystemWindows(rect)
會被執行。而
fitSystemWindows(rect)
方法是,當Window內容的邊距發生改變時(進入全屏化),允許調用該方法調正我們App的UI,以適應Window的變化。正常情況下,系統UI會入侵到AppUI的一些空間(狀態欄,輸入法,導航欄等),也就是我們App的UI不會出現在系統UI之下。
不過萬一你使用了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION ,你的內容可能會被系統UI覆蓋。此時,你能調用這個方法,來確保你的UI不會被系統的UI覆蓋。
這個方法的簡單實現是使用padding來做到的,並且這個方法默認是不執行的。
其實,在橫屏全屏狀態下,之所以EditText不會被輸入法遮擋,都是由於執行了這個方法
Java和Android架構
Java和Android架構是一個數萬人關注的探討Java和Android開發的公衆號,分享和原創最有價值的乾貨文章,讓你成爲這方面的大牛!
我們探討android和Java開發最前沿的技術:android性能優化 ,插件化,跨平臺,動態化,加固和反破解等,也討論設計模式/軟件架構等。由一羣來自BAT的工程師組成的團隊。
關注即送紅包,回覆:“百度” 、“阿里”、“騰訊” 有驚喜!!!關注後可用入微信羣。羣裏都是來自百度阿里騰訊的大牛。
歡迎關注我們,一起討論技術,掃描和長按下方的二維碼可快速關注我們。或搜索微信公衆號:JANiubility。
公衆號:JANiubility