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

當(dāng)然,歡迎頁(yè)的圖片適配也同樣會(huì)出現(xiàn)問題。
Google后得出第一個(gè)問題的解決方案。第二個(gè)圖片的問題則用自己摸索的方式解決,當(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該問題而封裝的類,也可以看作是一個(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上有人為了適配軟鍵盤在全屏下的布局問題。
開始先判斷該設(shè)備上是否存在導(dǎo)航欄。為什么用findViewById(android.R.id.content)呢?因?yàn)閍ndroid.R.id.content這個(gè)id代表的就是所在頁(yè)面的根布局,而并不需要特別指定一個(gè)id給該布局。可以通過調(diào)用系統(tǒng)API返回的結(jié)果,也可以通過判斷該手機(jī)是否為華為手機(jī),操作系統(tǒng)屬于哪種類型來(lái)來(lái)判斷。
一旦確定該設(shè)備存在導(dǎo)航欄,將對(duì)該布局進(jìn)行重新測(cè)量。首先mChildOfContent得到其視圖樹,對(duì)全局高度實(shí)現(xiàn)監(jiān)聽。
OnGlobalLayoutListener 是ViewTreeObserver的內(nèi)部類,當(dāng)一個(gè)視圖樹的布局發(fā)生改變時(shí),可以被ViewTreeObserver監(jiān)聽到,這是一個(gè)注冊(cè)監(jiān)聽視圖樹的觀察者(observer),在視圖樹的全局事件改變時(shí)得到通知。ViewTreeObserver不能直接實(shí)例化,而是通過getViewTreeObserver()獲得。
接著得到視圖目前可用的總高度,將其賦值給mChildOfContent的布局高度。調(diào)用requestLayout,讓mChildOfContent要求自己的parent view對(duì)自己重新設(shè)置位置。
四、全屏圖片的適配
解決了布局的問題,再來(lái)看歡迎頁(yè)啟動(dòng)時(shí)候全屏圖片的適配問題。發(fā)現(xiàn)該方法對(duì)于圖片不適用。如下圖,當(dāng)虛擬按鍵彈出時(shí),圖片照樣被遮擋了底部的一小部分。

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

仔細(xì)想想,對(duì)于一個(gè)ImageView直接占據(jù)一個(gè)layout的情況,是沒有必要再去寫一些代碼進(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應(yīng)用中SimpleAdapter簡(jiǎn)單適配器的使用
這篇文章主要介紹了Android應(yīng)用中SimpleAdapter簡(jiǎn)單適配器的使用例子,SimpleAdapter經(jīng)常在ListView被使用,需要的朋友可以參考下2016-04-04
Android模擬用戶點(diǎn)擊的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Android模擬用戶點(diǎn)擊的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)學(xué)習(xí)學(xué)習(xí)吧。2018-02-02
Android?中的?Timer?和?TimerTask詳解
Timer?是?Java?中用于創(chuàng)建定時(shí)任務(wù)的類,它位于?java.util?包中,可以使用Timer來(lái)安排一次性或定期執(zhí)行的任務(wù),這篇文章主要介紹了Android?的?Timer?和?TimerTask,需要的朋友可以參考下2024-05-05
Android跳轉(zhuǎn)三方應(yīng)用實(shí)例代碼
大家好,本篇文章主要講的是Android跳轉(zhuǎn)三方應(yīng)用實(shí)例代碼,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
Android 實(shí)現(xiàn)桌面未讀角標(biāo)
本文主要介紹了Android實(shí)現(xiàn)桌面未讀角標(biāo)的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04
android橫豎屏切換時(shí)候Activity的生命周期
曾經(jīng)遇到過一個(gè)面試題,讓你寫出橫屏切換豎屏Activity的生命周期?,F(xiàn)在給大家分析一下他切換時(shí)具體的生命周期是怎么樣的2013-01-01
Android bindService的使用與Service生命周期案例詳解
這篇文章主要介紹了Android bindService的使用與Service生命周期案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
Android新特性ConstraintLayout完全解析
這篇文章主要為大家詳細(xì)介紹了Android新特性ConstraintLayout ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10

