這篇文章主要介紹了Android屏幕適配的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
創(chuàng)新互聯(lián)公司是一家專業(yè)的成都網(wǎng)站建設(shè)公司,我們專注網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷、企業(yè)網(wǎng)站建設(shè),買鏈接,1元廣告為企業(yè)客戶提供一站式建站解決方案,能帶給客戶新的互聯(lián)網(wǎng)理念。從網(wǎng)站結(jié)構(gòu)的規(guī)劃UI設(shè)計(jì)到用戶體驗(yàn)提高,創(chuàng)新互聯(lián)力求做到盡善盡美。
測(cè)試與思考
不得不說今日頭條的大神們的想法真的非常獨(dú)到,成本極其低廉,還特別好用。他們給出的最終方案是這樣的:
private static float sRoncompatDennsity; private static float sRoncompatScaledDensity; private void setCustomDensity(@NonNull Activity activity, final @NonNull Application application) { //application final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics(); if (sRoncompatDennsity == 0) { sRoncompatDennsity = appDisplayMetrics.density; sRoncompatScaledDensity = appDisplayMetrics.scaledDensity; application.registerComponentCallbacks(new ComponentCallbacks() { @Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig != null && newConfig.fontScale > 0) { sRoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; } } @Override public void onLowMemory() { } }); } //計(jì)算寬為360dp 同理可以設(shè)置高為640dp的根據(jù)實(shí)際情況 final float targetDensity = appDisplayMetrics.widthPixels / 360; final float targetScaledDensity = targetDensity * (sRoncompatScaledDensity / sRoncompatDennsity); final int targetDensityDpi = (int) (targetDensity * 160); appDisplayMetrics.density = targetDensity; appDisplayMetrics.densityDpi = targetDensityDpi; appDisplayMetrics.scaledDensity = targetScaledDensity; //activity final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; activityDisplayMetrics.scaledDensity = targetScaledDensity; }
看到這篇文章之后我趕緊就寫了一個(gè)demo測(cè)試了一下,發(fā)現(xiàn)了一點(diǎn)小問題。我們UI給出的設(shè)計(jì)圖尺寸為1334*720,如果我按照寬度作為適配標(biāo)準(zhǔn)的話,按照設(shè)計(jì)圖720px的寬度,屏幕的寬度應(yīng)為360dp,也就是這樣:
final float targetDensity = appDisplayMetrics.widthPixels / 360;
這樣做的話寬度適配的比例是沒有任何問的,但是我在想,如果需要以高度來做適配(也就是內(nèi)容剛好縱向填充全屏)的話,是不是改成這樣就可以了:
final float targetDensity = appDisplayMetrics.heightPixels / 667;
但是運(yùn)行之后發(fā)現(xiàn),高度上的差異很大,運(yùn)行在不同分辨率和尺寸的手機(jī)上,頁面中的每一部分內(nèi)容在縱向上的比例不盡相同,沒有達(dá)到很好的適配的效果。思考了許久過后我發(fā)現(xiàn)一個(gè)問題:我手邊的測(cè)試機(jī)的寬度是兩個(gè)720和兩個(gè)1080,而高度有1280,1440,1780和一個(gè)全面屏的2160。Android的開原性導(dǎo)致了Android設(shè)備的尺寸的碎片化太嚴(yán)重,而通過查看手機(jī)的尺寸參數(shù)會(huì)發(fā)現(xiàn),如果用這四個(gè)手機(jī)來測(cè)試的話,寬度可以直接整除,而高度不可以(并且我手邊的測(cè)試機(jī)的寬度也可以整除,如果有寬度沒法整除的手機(jī)呢?)。但是用今日頭條給出的方法,做除法后結(jié)果會(huì)取整,那會(huì)不會(huì)是由于用縱向計(jì)算出來的density取整影響了精度,從而導(dǎo)致了效果不盡人意呢?
問題修復(fù)
發(fā)現(xiàn)上述問題之后我就著手去修改,將計(jì)算結(jié)果取余后在賦值給targetDensity,經(jīng)過一下午的反復(fù)測(cè)試與實(shí)驗(yàn),我重新修改了targetDensity的計(jì)算方法:
float targetDensity = 0; try { Double division = Operation.division(appDisplayMetrics.heightPixels, 667); //由于手機(jī)的長寬不盡相同,肯定會(huì)有除不盡的情況,有失精度,所以在這里把所得結(jié)果做了一個(gè)保留兩位小數(shù)的操作 DecimalFormat df = new DecimalFormat("0.00"); String s = df.format(division); targetDensity = Float.parseFloat(s); } catch (NumberFormatException e) { e.printStackTrace(); }
經(jīng)測(cè)試后發(fā)現(xiàn),這樣取兩位小數(shù)計(jì)算過后,高度上的適配結(jié)果讓人非常滿意??墒沁€有一個(gè)問題,我們一般來說做適配都是以手機(jī)的寬度為基準(zhǔn),但是一個(gè)app里面避免不了偶爾一兩個(gè)頁面是按照高度為基準(zhǔn)(就是內(nèi)容縱向填充全屏的頁面)做適配的。但是上述方法只能保證一個(gè)方向,那我就讓它可以自由的切換適配的基準(zhǔn)方向不就好了。
最終方案
繼續(xù)修改之后我得到了最終的方案,修改過后這個(gè)類中的所有內(nèi)容如下:
private static float appDensity; private static float appScaledDensity; private static DisplayMetrics appDisplayMetrics; //此方法在Application的onCreate方法中調(diào)用 Density.setDensity(this); public static void setDensity(@NonNull Application application) { //獲取application的DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics(); if (appDensity == 0) { //初始化的時(shí)候賦值(只在Application里面初始化的時(shí)候會(huì)調(diào)用一次) appDensity = appDisplayMetrics.density; appScaledDensity = appDisplayMetrics.scaledDensity; //添加字體變化的監(jiān)聽 application.registerComponentCallbacks(new ComponentCallbacks() { @Override public void onConfigurationChanged(Configuration newConfig) { //字體改變后,將appScaledDensity重新賦值 if (newConfig != null && newConfig.fontScale > 0) { appScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; } } @Override public void onLowMemory() { } }); } //調(diào)用修改density值的方法(默認(rèn)以寬度作為基準(zhǔn)) setAppOrientation(null, AppUtils.WIDTH); } //此方法用于在某一個(gè)Activity里面更改適配的方向 Density.setOrientation(mActivity, "width/height"); public static void setOrientation(Activity activity, String orientation) { setAppOrientation(activity, orientation); } /** * targetDensity * targetScaledDensity * targetDensityDpi * 這三個(gè)參數(shù)是統(tǒng)一修改過后的值 * * orientation:方向值,傳入width或height */ private static void setAppOrientation(@Nullable Activity activity, String orientation) { float targetDensity = 0; try { Double division; //根據(jù)帶入?yún)?shù)選擇不同的適配方向 if (orientation.equals("height")) { //appDisplayMetrics.heightPixels/667 division = Operation.division(appDisplayMetrics.heightPixels, 667); } else { division = Operation.division(appDisplayMetrics.widthPixels, 360); } //由于手機(jī)的長寬不盡相同,肯定會(huì)有除不盡的情況,有失精度,所以在這里把所得結(jié)果做了一個(gè)保留兩位小數(shù)的操作 DecimalFormat df = new DecimalFormat("0.00"); String s = df.format(division); targetDensity = Float.parseFloat(s); } catch (NumberFormatException e) { e.printStackTrace(); } float targetScaledDensity = targetDensity * (appScaledDensity / appDensity); int targetDensityDpi = (int) (160 * targetDensity); /** * * ***在這里將修改過后的值賦給系統(tǒng)參數(shù) * * (因?yàn)樽铋_始初始化的時(shí)候,activity為null,所以只設(shè)置application的值就可以了... * 所以在這里判斷了一下,如果傳有activity的話,再設(shè)置Activity的值) */ if (activity != null) { DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.scaledDensity = targetScaledDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; } else { appDisplayMetrics.density = targetDensity; appDisplayMetrics.scaledDensity = targetScaledDensity; appDisplayMetrics.densityDpi = targetDensityDpi; } }
這是修改之后的所有內(nèi)容,不懂的地方可以看一下里面的注釋,在里面我是默認(rèn)的以寬度來作為基準(zhǔn)(這是在Activity中設(shè)置的方法,存在于此Activity下的fragment,dialog和PopupWindow都會(huì)受到此效果的影響,也就是說,在Activity中設(shè)置一次之后,Activity下的其他子View都無需再設(shè)置一次)。
使用方法
自己創(chuàng)建一個(gè)類,將最終方案里面的代碼復(fù)制粘貼就可以使用了
使用方法:在Application的onCreate()方法中
如果只是適配一個(gè)方向的話,只設(shè)置這一句就可以了(我在utils里面設(shè)置了默認(rèn)按照寬度適配,可以根據(jù)自己的需求修改默認(rèn)的適配方向,見下圖)
若app中有某一個(gè)頁面需要縱向適配的話:
/** * * 由于是個(gè)人封裝,此方法需要寫在onCreate()中的setContentView()方法前面,切換方向的效果才會(huì)生效 */ @Override public void setOrientation() { Density.setOrientation(this, AppUtils.HEIGHT); } /** * * 如果在一個(gè)Activity里面切換了適配方向的話,需要在destroy里面將方向設(shè)置為默認(rèn)的方向, * 因?yàn)榍袚Q方向修改的是Activity的值,但是application的也會(huì)覆蓋掉(原因還沒有搞清楚...), * 權(quán)衡利弊之后就在onDestroy這個(gè)生命周期里面重新初始化了一下方向(因?yàn)橛酶叨茸鳛檫m配基準(zhǔn)的頁面 * 少之又少,這樣可以***程度的減少對(duì)程序功能性的影響) */ @Override protected void onDestroy() { super.onDestroy(); Density.setOrientation(this, AppUtils.WIDTH); }
由于在某一個(gè)Activity里面切換方向之后,我修改掉的是Activity中的值(activityDensity),但是返回再點(diǎn)擊其他頁面之后發(fā)現(xiàn)其他頁面的適配方向也被修改掉了,于是乎權(quán)衡利弊之后我就用了這個(gè)相對(duì)來說影響最小的辦法:在需要修改適配方向的Activity中的onDetroy生命周期里面,再手動(dòng)將方向改成默認(rèn)。。。(搗鼓了很久實(shí)在是想不到更好的辦法了,如果各位看官有其他的好辦法可以給我留言)。
***貼出縱向適配的效果圖,頁面中藍(lán)色背景的TextView高度是固定的150dp(只是我自己寫的一個(gè)很簡(jiǎn)單的頁面,不要嫌丑。。。):
敲黑板!!!
用此方法寫適配,只需要一個(gè)dimens文件,一個(gè)layout文件就足矣,在xml布局中直接只用dp就可以了(Android P的劉海屏需要單獨(dú)適配layout,全面屏手機(jī)可以隱藏的虛擬按鍵似乎也需要單獨(dú)適配。。。)
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Android屏幕適配的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!
新聞名稱:Android屏幕適配的示例分析
分享路徑:http://muchs.cn/article30/jsojso.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、品牌網(wǎng)站設(shè)計(jì)、營銷型網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)頁設(shè)計(jì)公司、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)