前言
由于我之前是在一些設(shè)備原廠工作的只需要負責(zé)sdk的工作以及去給客戶駐點開發(fā)的,基本不會涉及到屏幕適配,就算是客戶那邊也是固定的一個Android設(shè)備不需要適配;隨著我離職之后去面試別的公司,人家一問到我屏幕適配時候我回答不出來,故此我花了些時間研究網(wǎng)上所說的屏幕適配,然后我總結(jié)借鑒了一下。
屏幕分辨率限定符與 smallestWidth 限定符適配原理
屏幕分辨率限定符適配原理
屏幕分辨率限定符適配需要在 res 文件夾下創(chuàng)建各種屏幕分辨率對應(yīng)的 values-xxx 文件夾,如下圖:

這樣設(shè)計圖里面顯示多少px就可以這么寫@dimen/x720或者@dimen/y720,相應(yīng)的屏幕配比會自動加載相應(yīng)配比的資源文件,
UI設(shè)計的尺寸是多少那就按照那個比例為基準(zhǔn)生成對應(yīng)的資源,比如UI給的是720*1280的(這個單位是px,dpi=160) 然后我就會以那個為基準(zhǔn)生成一套資源文件


代碼在MakeXml,然后UI設(shè)計上標(biāo)志是多少px,在資源引用時候就使用多少px

缺點:這個方案缺點很明顯,只適用常規(guī)的手機屏幕尺寸。
這個方案的還有鴻洋老鐵的https://blog.csdn.net/lmj623565791/article/details/45460089
效果圖:




smallestWidth 限定符 適配原理
smallestWidth 限定符適配原理與屏幕分辨率限定符適配原理一樣,系統(tǒng)都是根據(jù)限定符去尋找對應(yīng)的 dimens.xml 文件。例如程序運行在最小寬度為 360dp 的設(shè)備上,系統(tǒng)會自動找到對應(yīng)的 values-sw360dp 文件夾下的 dimens.xml 文件。區(qū)別就在于屏幕分辨率限定符適配是拿 px 值等比例縮放,而 smallestWidth 限定符適配是拿 dp 值來等比縮放而已。需要注意的是“最小寬度”是不區(qū)分方向的,即無論是寬度還是高度,哪一邊小就認為哪一邊是“最小寬度”。如下分別為最小寬度為 360dp 與最小寬度為 640dp 所對應(yīng)的 dimens.xml 文件:

獲取設(shè)備最小寬度代碼為:
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int heightPixels = ScreenUtils.getScreenHeight(this);
int widthPixels = ScreenUtils.getScreenWidth(this);
float density = dm.density; float heightDP = heightPixels / density;
float widthDP = widthPixels / density;
float smallestWidthDP;
if(widthDP < heightDP) {
????smallestWidthDP = widthDP;
}else {
????smallestWidthDP = heightDP;
}
ScreenUtils——>ScreenUtils
使用步驟
1、以設(shè)計圖最小寬度(單位為 dp)作為基準(zhǔn)值,生成所有設(shè)備對應(yīng)的 dimens.xml 文件
? ? 這個可以使用工具ScreenMatch工具,具體怎么使用我這里就不解釋了,網(wǎng)上很多資料
2、根據(jù)設(shè)計圖標(biāo)注,在布局寫上對應(yīng)的值。
設(shè)計圖標(biāo)注多少 dp,布局中就寫多少 dp ,非常方便!
如果需要動態(tài)設(shè)置尺寸
/*獲取sp值*/
float pxValue = getResources().getDimension(R.dimen.sp_15);//獲取對應(yīng)資源文件下的sp值
int spValue = ConvertUtils.px2sp(this, pxValue);//將px值轉(zhuǎn)換成sp值
mTvShowParams.setTextSize(spValue);//設(shè)置文字大小 /*獲取dp值*/
float pxValue2 = getResources().getDimension(R.dimen.dp_360);//獲取對應(yīng)資源文件下的dp值
int dpValue = ConvertUtils.px2dp(this, pxValue2);//將px值轉(zhuǎn)換成dp值
使用步驟總結(jié)
說了這么多,其實只需要簡單的 2 步:
以設(shè)計圖最小寬度(單位為 dp)作為基準(zhǔn)值,利用插件生成所有設(shè)備對應(yīng)的 dimens.xml 文件
根據(jù)設(shè)計圖標(biāo)注,標(biāo)注多少 dp,布局中就寫多少dp,格式為@dimen/dp_XX。(注意:UI給到的圖如果是px單位的話你就得換算成dp單位的,例如:UI給的是1920*1080 單位是px然后你問清楚這個是對應(yīng)320dp*480dp的屏幕還是哪一款,最后是根據(jù)那個dp來標(biāo)注的,個人理解,比如我那個“益糯健康這個控件距離頂部是126px,但是以dp標(biāo)記缺失63dp”)
缺點:寬度可以適配了但是高度沒辦法,

ConstraintLayout新布局 具體鴻洋老鐵;
鴻洋 AutoLayout全新的適配方式 堪稱適配終結(jié)者
AutoLayout我就不介紹了? 原文肯定講的更好聽
今日頭條適配方案
因為Android中的dp在渲染前會將dp轉(zhuǎn)換成px,計算公式:
px = density * dp;
density = dpi/160;
px = dp * (dpi/160);
屏幕尺寸、分辨率】像素密度三者關(guān)系

舉個例子:屏幕分辨率為:1920*1080,屏幕尺寸為5吋的話,那么dpi為440。
這樣會遇到一些問題:假設(shè)我們UI設(shè)計圖是按屏幕寬度為360dp來設(shè)計的,那么在上述設(shè)備上,屏幕寬度其實為1080/(440/160)=392.7dp,也就是屏幕是比設(shè)計圖要寬的。這種情況下, 即使使用dp也是無法在不同設(shè)備上顯示為同樣效果的。 同時還存在部分設(shè)備屏幕寬度不足360dp,這時就會導(dǎo)致按360dp寬度來開發(fā)實際顯示不全的情況。
而且上述屏幕尺寸、分辨率和像素密度的關(guān)系,很多設(shè)備并沒有按此規(guī)則來實現(xiàn), 因此dpi的值非常亂,沒有規(guī)律可循,從而導(dǎo)致使用dp適配效果差強人意。
所以我們得從dp和px的轉(zhuǎn)換公式 :px = dp * density 入手
可以看出,如果設(shè)計圖寬為360dp,想要保證在所有設(shè)備計算得出的px值都正好是屏幕寬度的話,我們只能修改 density 的值。
通過閱讀源碼,我們可以得知,density 是 DisplayMetrics 中的成員變量,而 DisplayMetrics 實例通過Resources#getDisplayMetrics可以獲得,而Resouces通過Activity或者Application的Context獲得。
先來熟悉下 DisplayMetrics 中和適配相關(guān)的幾個變量:
DisplayMetrics#density?就是上述的density
DisplayMetrics#densityDpi?就是上述的dpi
DisplayMetrics#scaledDensity字體的縮放因子,正常情況下和density相等,但是調(diào)節(jié)系統(tǒng)字體大小后會改變這個值
所以我們完全可以修改DisplayMetrics的相關(guān)數(shù)據(jù)來解決問題,
具體使用看UI給的是尺寸? 我這邊的例子是1280*800然后dpi為160的

剩下的就是根據(jù)設(shè)計圖上面的標(biāo)注的距離和字體直接填寫就好了,
不過注意調(diào)用前是在setContentView()前調(diào)用
Density.setDensity(this);
Density.setDefault(this);
具體代碼demo
具體我借鑒的原文在這? ——字節(jié)跳動
其實適配還有很多,這些只是我使用過的,具體呢都是使用步驟,你們要是想了解更實際的得自己深究了