基于界面適配華為手機(jī)的虛擬按鍵的解決方法
一、概述
在項(xiàng)目中,測(cè)試發(fā)現(xiàn)在一些華為手機(jī)的屏幕適配上出現(xiàn)了問(wèn)題,主要是因?yàn)槿A為Mate等一些系列的手機(jī)有一個(gè)虛擬按鍵的設(shè)計(jì)。當(dāng)這些虛擬按鍵由用戶手勢(shì)滑出,或默認(rèn)顯示的話,就會(huì)遮擋我們本身的應(yīng)用布局。比如歡迎界面過(guò)后是四個(gè)Fragment,那么底部的四個(gè)tab就會(huì)被虛擬的導(dǎo)航欄遮住,非常難看。

當(dāng)然,歡迎頁(yè)的圖片適配也同樣會(huì)出現(xiàn)問(wèn)題。
Google后得出第一個(gè)問(wèn)題的解決方案。第二個(gè)圖片的問(wèn)題則用自己摸索的方式解決,當(dāng)然也非常簡(jiǎn)單。
二、布局由于虛擬按鍵導(dǎo)致導(dǎo)航欄頂上去的解決方法
在我們的項(xiàng)目中加載Fragment的MainActivity,以及其他一般的Activity繼承的BaseActivity中的onCreate方法中添加如下代碼:
if (AndroidWorkaround.checkDeviceHasNavigationBar(this)) {
AndroidWorkaround.assistActivity(findViewById(android.R.id.content));
}
其中AndroidWorkaround使我們?yōu)榱私鉀Q該問(wèn)題而封裝的類,也可以看作是一個(gè)特定的工具類:
/**
* 解決底部屏幕按鍵適配
* Created by Mercury on 2016/10/25.
*/
public class AndroidWorkaround {
public static void assistActivity(View content) {
new AndroidWorkaround(content);
}
private View mChildOfContent;
private int usableHeightPrevious;
private ViewGroup.LayoutParams frameLayoutParams;
private AndroidWorkaround(View content) {
mChildOfContent = content;
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
frameLayoutParams.height = usableHeightNow;
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom);
}
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) {
}
return hasNavigationBar;
}
}
重新測(cè)試,發(fā)現(xiàn)無(wú)論是否彈出虛擬按鍵,都不會(huì)再次遮擋tab按鈕。
三、原理
上面的代碼需要在setContentView后面執(zhí)行。其最初的解決方案是stackoverflow上有人為了適配軟鍵盤在全屏下的布局問(wèn)題。
開(kāi)始先判斷該設(shè)備上是否存在導(dǎo)航欄。為什么用findViewById(android.R.id.content)呢?因?yàn)閍ndroid.R.id.content這個(gè)id代表的就是所在頁(yè)面的根布局,而并不需要特別指定一個(gè)id給該布局??梢酝ㄟ^(guò)調(diào)用系統(tǒng)API返回的結(jié)果,也可以通過(guò)判斷該手機(jī)是否為華為手機(jī),操作系統(tǒng)屬于哪種類型來(lái)來(lái)判斷。
一旦確定該設(shè)備存在導(dǎo)航欄,將對(duì)該布局進(jìn)行重新測(cè)量。首先mChildOfContent得到其視圖樹(shù),對(duì)全局高度實(shí)現(xiàn)監(jiān)聽(tīng)。
OnGlobalLayoutListener 是ViewTreeObserver的內(nèi)部類,當(dāng)一個(gè)視圖樹(shù)的布局發(fā)生改變時(shí),可以被ViewTreeObserver監(jiān)聽(tīng)到,這是一個(gè)注冊(cè)監(jiān)聽(tīng)視圖樹(shù)的觀察者(observer),在視圖樹(shù)的全局事件改變時(shí)得到通知。ViewTreeObserver不能直接實(shí)例化,而是通過(guò)getViewTreeObserver()獲得。
接著得到視圖目前可用的總高度,將其賦值給mChildOfContent的布局高度。調(diào)用requestLayout,讓mChildOfContent要求自己的parent view對(duì)自己重新設(shè)置位置。
四、全屏圖片的適配
解決了布局的問(wèn)題,再來(lái)看歡迎頁(yè)啟動(dòng)時(shí)候全屏圖片的適配問(wèn)題。發(fā)現(xiàn)該方法對(duì)于圖片不適用。如下圖,當(dāng)虛擬按鍵彈出時(shí),圖片照樣被遮擋了底部的一小部分。

如果隱藏虛擬按鍵,圖片大小恢復(fù)正常

仔細(xì)想想,對(duì)于一個(gè)ImageView直接占據(jù)一個(gè)layout的情況,是沒(méi)有必要再去寫一些代碼進(jìn)行適配的。到布局里一看,發(fā)現(xiàn)ImageView的屬性 android:scaleType=”centerCrop”
將其改為 android:scaleType=”fitXY”就可以解決了。這樣圖片可能高度會(huì)隨著虛擬鍵的彈出而壓縮,但是很好的適配了布局高度的變化而不會(huì)被遮擋。
關(guān)于scaleType的詳細(xì)介紹,留待其他文章里再探討。
以上這篇基于界面適配華為手機(jī)的虛擬按鍵的解決方法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Android自定義TextView仿微信朋友圈文字展開(kāi)全文功能
這篇文章主要為大家詳細(xì)介紹了Android自定義TextView仿微信朋友圈文字展開(kāi)全文功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
Android實(shí)現(xiàn)簡(jiǎn)單的banner輪播圖
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單的banner輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
Android序列化接口Parcelable與Serializable接口對(duì)比
我們使用 Intent 傳遞數(shù)據(jù)的時(shí)候,putExtra() 所支持的數(shù)據(jù)類型事有限的,當(dāng)需要傳遞自定義對(duì)象的時(shí)候就需要序列化。Serializable更簡(jiǎn)單但是會(huì)把整個(gè)對(duì)象進(jìn)行序列化因此效率比Parcelable低一些2023-02-02
Android實(shí)現(xiàn)圖片在屏幕內(nèi)縮放和移動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了Android控制圖片在屏幕內(nèi)縮放和移動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02
android開(kāi)發(fā)環(huán)境遇到adt無(wú)法啟動(dòng)的問(wèn)題分析及解決方法
開(kāi)始研究android開(kāi)發(fā),搭建開(kāi)發(fā)環(huán)境的時(shí)候就出了問(wèn)題,真是束手無(wú)策2013-02-02
Android中TextView文本高亮和點(diǎn)擊行為的封裝方法
這篇文章主要介紹了Android中TextView文本高亮和點(diǎn)擊行為的封裝方法,文中介紹的非常詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-03-03
利用Android設(shè)計(jì)一個(gè)倒計(jì)時(shí)組件
在很多電商工作項(xiàng)目中經(jīng)常有倒計(jì)時(shí)的場(chǎng)景,比如活動(dòng)倒計(jì)時(shí)、搶紅包倒計(jì)時(shí)等等,今天小編就帶大家來(lái)學(xué)習(xí)如何利用Android設(shè)計(jì)倒計(jì)時(shí)組件,感興趣的小伙伴一起奧2021-09-09
簡(jiǎn)單好用的Adapter---ArrayAdapter詳解
這篇文章主要介紹了簡(jiǎn)單好用的Adapter---ArrayAdapter詳解,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11

