小豬淺談Android屏幕適配

tags: Tutorial


引言

??????國(guó)慶前在微信群里看到有人在問(wèn)Android屏幕適配的問(wèn)題,湊巧自己最近時(shí)間
略有閑暇,索性來(lái)談?wù)凙ndroid中屏幕適配相關(guān)的一些內(nèi)容吧,鄙人才疏學(xué)淺,
所說(shuō)的都是自己認(rèn)知范圍以?xún)?nèi)的,不可能面面俱到,如有疏漏不妥之處,還請(qǐng)
不吝指出,謝謝!配上最近被玩壞的Gif~


Android中的單位與名詞


1.相對(duì)單位與絕對(duì)單位

對(duì)于計(jì)量單位,人們?nèi)粘A?xí)慣性分為「相對(duì)單位」與「絕對(duì)單位」兩類(lèi),前者
根據(jù)不同的情景表現(xiàn)出不同的大小,比如Android里的dp,px與sp等;而后者則是
制定了一個(gè)標(biāo)準(zhǔn),cm(厘米),寫(xiě)死了,就那么多,1cm什么情況下都是一樣大。

說(shuō)到這個(gè)絕對(duì)單位,順帶提下兩個(gè)單位:

  • in(英寸)1 in = 2.54cm
  • pt(磅,印刷行業(yè)常用單位):1 pt = 1 / 72 in

2.px (pixel,像素)

就是一個(gè)個(gè)的像素點(diǎn),圖像的最小組成單元


3.dp (dip,密度無(wú)關(guān)像素)

Density-independent pixel,抽象意義上的像素與設(shè)備的實(shí)際物理像素點(diǎn)無(wú)關(guān),
可以保證在不同的像素密度的設(shè)備上顯示相同的效果,也是Android獨(dú)有的長(zhǎng)度單位。

1dp表示在屏幕像素密度為160dpi的屏幕上,1dp = 1px
類(lèi)推,在320dpi上,1dp = 2px,不難看出這樣的轉(zhuǎn)換公式:px = dp * (dpi / 160)


4.sp (sip,獨(dú)立比例像素)

scale-independent pixel,字體大小專(zhuān)用單位,會(huì)根據(jù)系統(tǒng)設(shè)置的字體大小進(jìn)行
縮放
,推薦使用12sp以上的字體(12sp以下太小),不推薦用奇數(shù)和小數(shù),容易造成
精度丟失問(wèn)題。

Tip

盡管官方建議我們字體都用sp作為單位,但是sp字體會(huì)根據(jù)系統(tǒng)設(shè)置的字體大小進(jìn)行
縮放,假如用戶(hù)修改了系統(tǒng)字體大小,可能會(huì)導(dǎo)致我們APP的UI受到影響,比如字體
大了,然后各種顯示不全,個(gè)人還是建議使用dp來(lái)做為字體單位!


5.手機(jī)外觀(guān)尺寸

整個(gè)手機(jī)的尺寸,不止屏幕,一般在中關(guān)村或者其他評(píng)測(cè)網(wǎng)站都可以查到。
一般是用mm為單位,依次為長(zhǎng) x 寬 x 厚度,比如我的老掉牙的moto x 的尺寸就是:
159.3mm × 83mm × 10.1mm。


6.屏幕尺寸

屏幕對(duì)角線(xiàn)的長(zhǎng)度,單位是英寸,計(jì)算公式如下:

其實(shí)就是勾股定理求對(duì)角線(xiàn)長(zhǎng)度,比如長(zhǎng)4寸,寬3寸的手機(jī),他的屏幕

尺寸計(jì)算:

7.分辨率(Resolution)

屏幕豎直方向與水平方向的像素個(gè)數(shù),比如:1280*720 就說(shuō)明屏幕的
豎直方向上有1280個(gè)像素點(diǎn),而水平方向上有720個(gè)像素點(diǎn),單位px。


8.dpi與ppi

  • dpi:dot per inch,點(diǎn)密度每英寸多少個(gè)點(diǎn),一般用作表示印刷品點(diǎn)密度;
  • ppi:pixels per inch,像素密度,每英寸所包含的像素?cái)?shù)目;
    一般用作表示顯示設(shè)備的點(diǎn)密度。

兩者的值近乎相等,不用過(guò)于糾結(jié)!這個(gè)值的計(jì)算公式如下:


9.density(屏幕密度)

這個(gè)單位感覺(jué)是用來(lái)表示不同dpi的倍數(shù)關(guān)系,計(jì)算公式:density = dpi/160


10.常用單位轉(zhuǎn)換工具類(lèi)

public class DensityUtil {
    public static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    public static int px2dp(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    public static int px2sp(Context context, float pxValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }

    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }
}


11.獲取屏幕尺寸與密度的三種方法

public class GetScreenParameter {  
    //方法一:已過(guò)時(shí),可使用,但不建議使用  
    public static void getResolution1(Context mContext) {  
        Display mDisplay = ((Activity) mContext).getWindowManager()  
                .getDefaultDisplay();  
        int W = mDisplay.getWidth();  
        int H = mDisplay.getHeight();  
    }  
    
    //方法二:通過(guò)getWindowManager來(lái)獲取屏幕尺寸的  
    public static void getResolution2(Context mContext) {  
        DisplayMetrics mDisplayMetrics = new DisplayMetrics();  
        ((Activity) mContext).getWindowManager().getDefaultDisplay()  
                .getMetrics(mDisplayMetrics);  
        int W = mDisplayMetrics.widthPixels;  
        int H = mDisplayMetrics.heightPixels;  
        // 屏幕密度(0.75 / 1.0 / 1.5)        
        float density = mDisplayMetrics.density;
        // 就是屏幕密度 * 160而已,屏幕密度DPI(120 / 160 / 240)
        int densityDpi = mDisplayMetrics.densityDpi; 
    }  
    
    //方法三:通過(guò)getResources來(lái)獲取屏幕尺寸的,大部分用這個(gè)
    public static void getResolution3(Context mContext) {  
        DisplayMetrics mDisplayMetrics = new DisplayMetrics();  
        mDisplayMetrics = mContext.getResources().getDisplayMetrics();  
        int W = mDisplayMetrics.widthPixels;  
        int H = mDisplayMetrics.heightPixels;  
        float density = mDisplayMetrics.density;   
        int densityDpi = mDisplayMetrics.densityDpi; 
    }  
}  

Tip(可以不看,現(xiàn)在基本不會(huì)用這么小屏的手機(jī)了):

對(duì)于屏幕密度很低的小屏手機(jī),比如240320,計(jì)算出來(lái)的尺寸,可能為:320427
原因是:沒(méi)有設(shè)置多分辨率支持的話(huà),Android系統(tǒng)會(huì)將240x320的低密度(120)尺寸
轉(zhuǎn)換為中等密度160dpi對(duì)應(yīng)的尺寸,如果你想獲得正確的物理尺寸,需要在
AndroidManifest.xml里添加下述代碼:

<supports-screens  
    android:smallScreens="true"  
    android:normalScreens="true"  
    android:largeScreens="true"  
    android:resizeable="true"  
    android:anyDensity="true"/>

Android適配準(zhǔn)備


1.什么是Android適配

答:因?yàn)锳ndroid系統(tǒng)的開(kāi)放性,很多廠(chǎng)商都喜歡對(duì)Android系統(tǒng)和硬件進(jìn)行個(gè)性化定制,
以達(dá)到他們想要的樣子,這種結(jié)果帶來(lái)的「Android系統(tǒng)」和「手機(jī)屏幕」的碎片化問(wèn)題
只對(duì)市場(chǎng)占用率較高的720和1080進(jìn)行適配顯然是不夠的,為了讓我們的Android應(yīng)用在各種
各樣的手機(jī)上保證界面效果一致,各種手機(jī)屏幕的適配顯得非常重要,也是每個(gè)開(kāi)發(fā)者
為之頭痛的問(wèn)題。


2.Android中的六種通用屏幕密度

屏幕密度 范圍(dpi) 標(biāo)準(zhǔn)分辨率 dp與px 圖標(biāo)尺寸
ldpi(QVGA) ~ 120 240 * 320 1dp=0.75px 36 * 36
mdpi(HVGA) 120 ~ 160 320 * 480 1dp=1px 48 * 48
hdpi(WVGA) 160 ~ 240 480 * 800 1dp=1.5px 72 * 72
xhdpi(720P) 240 ~ 320 720 * 1280 1dp=2px 96 * 96
xxhdpi(1080p) 320 ~ 480 1080 * 1920 1dp=3px 144 * 144
xxxhdpi(2K) 480 ~ 640 1440 × 2560 1dp=4px 192 * 192

Tip:圖標(biāo)大小 = px數(shù) * 4 * 12


3.關(guān)于UI設(shè)計(jì)稿的適配

我們可以通過(guò)友盟的 全域羅盤(pán) 知道當(dāng)前國(guó)內(nèi)的移動(dòng)設(shè)備使用情況,
以此了解需要適配的趨勢(shì),以八月份的統(tǒng)計(jì)為例,截取屏幕尺寸與分辨率占比
拍醒前五的數(shù)據(jù)如下:

??

更多詳細(xì)信息可自行查看,從上面兩個(gè)表格不難看出這樣的趨勢(shì):

5.5寸5寸 屏幕尺寸市場(chǎng)占比最高,而分辨率:1920x10801280x720
依舊是當(dāng)前主流。

也就是說(shuō)讓設(shè)計(jì)師按照720p和1080p出兩套設(shè)計(jì)稿就可以適配大部分的
設(shè)備了,但是不同的公司因?yàn)槿藛T或者時(shí)間等外部因素,可能有這幾
種情況:

  • 三套:720p,1080p,1440p,這是最理想的情況;
  • 兩套:720p,1080p,主流,大部分公司都或走兩套;
  • 一套:720p,又或者和iOS共用一套 750x1334,可以當(dāng)做720p的設(shè)計(jì)稿
    來(lái)編寫(xiě)UI,盡管比例和接近16:9,但是還是有些偏差,需要Android對(duì)UI進(jìn)行微調(diào)!

UI能做的基本就到這里了,至于其他分辨率的手機(jī)則需要我們開(kāi)通過(guò)
相關(guān)的手段來(lái)適配了。


Android適配開(kāi)始


1.最簡(jiǎn)單一些適配技巧

先來(lái)說(shuō)幾個(gè)爛大街的適配技巧吧

1) 使用dp而非px

dp是像素?zé)o關(guān)的,而在實(shí)際使用中1dp大約等于1/160 in,比如一個(gè)160dp * 160dp
的控件,在大多數(shù)的屏幕上都能保持1 in * 1 in 的大小。

但是,并不是能解決所有問(wèn)題的,以下兩點(diǎn)要注意:

  • 1.實(shí)際效果還是會(huì)有些差距的,僅僅是相近而已;
  • 2.當(dāng)設(shè)備的物理尺寸存在差異的時(shí)候,dp就顯得無(wú)能為力了。
    比如,為4.3寸屏幕準(zhǔn)備的UI,運(yùn)行在5.0寸的屏幕上,很可能在
    右側(cè)和下側(cè)存在大量的空白;而5.0寸的UI運(yùn)行到4.3寸的設(shè)備上,很可能顯示不下。

2) 少寫(xiě)固定尺寸

少寫(xiě)固定尺寸,而使用 wrap_content, match_parentweight 權(quán)重 」


3) 使用相對(duì)布局,不要使用絕對(duì)布局

常識(shí),而且絕對(duì)布局基本退出歷史舞臺(tái)了,可以忽略...


4) 自動(dòng)拉伸的.9圖

常識(shí),.9圖的作用是:拉伸的時(shí)候特定的區(qū)域不會(huì)發(fā)生圖片失真,而不失真的區(qū)域
可以由我們自己繪制,從而實(shí)現(xiàn)圖片適配。


5) 使用shape代替純色圖片

常識(shí),一些純色的矩形,圓角,圓都可以通過(guò)編寫(xiě)shape文件來(lái)替換,比起png,
xml文件小太多。


6)使用SVG矢量圖替換位圖

可能有些朋友對(duì)SVG矢量圖有些陌生,其實(shí)和普通的位圖最大的區(qū)別就是:
SVG是通過(guò)「XML文件」來(lái)定義一個(gè)圖形,通過(guò)一些特定的語(yǔ)法和規(guī)則來(lái)繪制
出我們所需的圖像,而不是位圖那樣通過(guò)存儲(chǔ)圖像中每一點(diǎn)的像素值來(lái)保存
與使用圖形。

SVG是已經(jīng)定義好怎么畫(huà)這個(gè)圖,需要的時(shí)候再去畫(huà),因?yàn)槭前凑仗囟ǖ恼Z(yǔ)法
和規(guī)則,理論上支持任何級(jí)別的縮放,而且不會(huì)失真,相比起多套同樣的位圖
文件,方便太多。

矢量圖雖好,但是有幾點(diǎn)要注意的:

  • 1.適用于A(yíng)ndroid 5.0以上,盡管官方有兼容包,低版本還是會(huì)有些問(wèn)題的!
  • 2.不適合細(xì)節(jié)過(guò)于復(fù)雜的圖片!
  • 3.因?yàn)槭怯玫降臅r(shí)候才畫(huà),所以加載圖片所消耗的時(shí)間和資源可能會(huì)增加。

至于怎么用這個(gè)矢量圖,你可以讓美工在PS里把圖片導(dǎo)出為SVG/PSD格式,然后
AS里右鍵drawable文件夾:

選中本地文件,確定

然后AS會(huì)幫你自動(dòng)生成一個(gè)矢量xml文件,比如我的一個(gè)tab圖標(biāo)

右側(cè)可以看到預(yù)覽圖:

然后要用到圖片的地方直接引用即可。
至于SVG的規(guī)則以及如何自行編寫(xiě)不在本節(jié)重點(diǎn),有興趣的可自行搜索用法~


2.多套資源文件的套路

常用的套路依舊不能解決大部分的屏幕適配問(wèn)題,Android給我們提供了
備用資源這個(gè)東西,詳細(xì)可見(jiàn)官網(wǎng):提供備用資源
簡(jiǎn)單說(shuō)就是按照規(guī)范,創(chuàng)建屏幕對(duì)應(yīng)的資源文件夾和資源文件,
Android會(huì)自動(dòng)去加載對(duì)應(yīng)文件夾里的資源的值,可能表述得有些不清晰,
舉個(gè)簡(jiǎn)單的例子:

比如我們xxhdpi,padding為3dp,而在xxxhdpi下的padding為5dp
我們就可以創(chuàng)建一個(gè)對(duì)應(yīng)的values文件夾和dimens.xml文件

相信你看到這里就明了,官網(wǎng)寫(xiě)的這個(gè)也就清晰了

而這個(gè)qualifier限定符怎么拼接可以看官網(wǎng),或者看下面的簡(jiǎn)表:

看到這里,你可能會(huì)有問(wèn)題,我要寫(xiě)多少套?
講真,我也不知道,只能說(shuō)看需要,但是想跟你說(shuō)限定符里一個(gè)很常用的:smallestWidth
屏幕區(qū)域的最小尺寸,比如 values-sw320dp,只有在屏幕寬度不小于
320dp的才會(huì)使用這個(gè)文件夾里的dimens.xml文件,我們還可以另外建立一個(gè)
values-sw360dp,然后320dp那個(gè)文件夾只有在屏幕寬度在320dp到360dp
內(nèi)才回去調(diào)用了,drawable,layout等資源文件也是同樣的套路。


3.使用腳本對(duì)長(zhǎng)度按照不同分辨率進(jìn)行比例轉(zhuǎn)換

就是拿屏幕寬度,去除以360,得出比例去乘以對(duì)應(yīng)的dp值
比如:sw720dp里一個(gè)單位的1 dp = 2dp,而sw800dp里的1 dp = 2.22dp:

Github地址:https://github.com/mengzhinan/PhoneScreenMatch

具體的自己看文檔和代碼吧,可能有的疑問(wèn)就是不是win電腦執(zhí)行不了bat文件
的問(wèn)題,比如mac,直接命令行,cd到 PhoneScreenMatch/app/src/main
目錄下,鍵入下述命令即可:

java -jar screenMatchPX.jar

項(xiàng)目中還提供了一個(gè)px適配的,分開(kāi)寬高做等值縮放的,對(duì)于長(zhǎng)寬比很奇葩
的機(jī)子可以試試。當(dāng)然這種適配方式帶來(lái)的最明顯的問(wèn)題就是資源文件增加
的問(wèn)題,這需要自行權(quán)衡。

類(lèi)似的方案還有:https://github.com/paulyung541/EasyScreen


4.[過(guò)時(shí)] 百分比布局庫(kù)支持庫(kù)

這個(gè)庫(kù)API 26.0.0 后的版本已經(jīng)棄用了,在官方倉(cāng)庫(kù)可以看到

[DEPRECATED in support lib v26] you should now use ConstraintLayout widget

如果你想使用百分比來(lái)編寫(xiě)建議使用約束布局 ConstraintLayout。
所以android-percent-support怎么用并不講,想通過(guò)看看源碼的方式
來(lái)了解百分比的實(shí)現(xiàn)套路,沒(méi)興趣的可以跳過(guò)了,或者看其他關(guān)于
百分比布局支持庫(kù)的其他使用擴(kuò)展文章:

源碼過(guò)一過(guò) (流程參照CSDN張鴻洋的博文)

lib庫(kù)里的東西不多,就三個(gè)核心的類(lèi)而已

如果讓我們來(lái)做套路可能是:

  • 通過(guò)LayoutParams獲取布局中設(shè)置的與百分比有關(guān)的屬性
  • 父布局拿到這些屬性值后進(jìn)行動(dòng)態(tài)計(jì)算,比如寬*寬占百分比
  • 子控件調(diào)用measure(計(jì)算后值)進(jìn)行繪制。

看下代碼具體是怎么做的,首先是獲取Layout里子控件的屬性,打開(kāi)
PercentFrameLayout,重寫(xiě)了generateLayoutParams方法,
然后新建了一個(gè)LayoutParams對(duì)象

看看這個(gè)LayoutParams里賣(mài)的什么藥:

通過(guò)PercentLayoutHelpergetPercentLayoutInfo方法構(gòu)造一個(gè)
PercentLayoutInfo對(duì)象,而getPercentLayoutInfo里做的事則
是把a(bǔ)ttrs里的東東都拿出來(lái),然后塞到PercentLayoutInfo對(duì)象用于返回:

而這個(gè)PercentLayoutInfo里定義了一堆百分比相關(guān)的屬性,
還有一些方法,字面上大概可以知道是設(shè)置LayoutParams相關(guān)
的方法,就是把onMeasure里的邏輯操作抽取到了這里。

好的,屬性拿到了,接著就是跟onMeasure方法了,調(diào)用了
PercentLayoutHelper對(duì)象里的adjustChildren方法

方法里做的東西也比較簡(jiǎn)單,拿到布局的寬高,然后
循環(huán)遍歷布局里的子控件,如果params是百分比類(lèi)型的
取出PercentLayoutInfo里info,然后去設(shè)置寬,高和margin。

再跟下fillLayoutParams方法,保存原本寬高后(后面用來(lái)重置),重新設(shè)置寬高,
fillMarginLayoutParams也是類(lèi)似,百分比的基本套路就已經(jīng)完了。

不過(guò)項(xiàng)目中還多了兩個(gè)細(xì)節(jié),計(jì)算值過(guò)小的情況以及重置原布局尺寸
onMeasure最后還調(diào)用handleMeasuredStateTooSmall方法,而方法做的
事是出去容器中所有的子控件,如果params是百分比類(lèi)型的,則調(diào)用
shouldHandleMeasuredWidthTooSmall方法判斷值是不是太小,太小則
把寬或高設(shè)置為ViewGroup.LayoutParams.WRAP_CONTENT(圖中 = -2那里)
needsSecondMeasure設(shè)置為true,代表需要二次重繪。

重置布局尺寸的代碼則是寫(xiě)在onLayout方法里(onMeasure后會(huì)回調(diào))

一樣是遍歷子控件,然后把參數(shù)都重置為之前存mPreservedParams里的值,
而這個(gè)值是布局里設(shè)置的0dp。(感覺(jué)沒(méi)什么用處...)

因?yàn)閛nMeasure的關(guān)鍵代碼都寫(xiě)到Helper類(lèi)里,擴(kuò)展一個(gè)百分比的線(xiàn)性
布局也很簡(jiǎn)單,拷貝下PercentFrameLayout改點(diǎn)東西就好。
另外,因?yàn)橐蕾?lài)于父容器,導(dǎo)致ScrollView,ListView等容器內(nèi)高度無(wú)法使用百分比
而鴻洋還另外對(duì)官方的百分比進(jìn)行了擴(kuò)展,寫(xiě)了一個(gè)android-percent-support-extend,
有興趣可以移步到他的博客閱讀:Android 增強(qiáng)版百分比布局庫(kù) 為了適配而擴(kuò)展


5.[作者停止維護(hù)] AndroidAutoLayout

又是鴻洋大神的庫(kù),不過(guò)作者已經(jīng)不維護(hù)了,使用之前還是三思?。?!
博客鏈接:http://blog.csdn.net/lmj623565791/article/details/49990941

大概套路是

定好設(shè)計(jì)稿尺寸,直接選擇對(duì)應(yīng)分辨率的預(yù)覽,AndroidAutoLayout 庫(kù)會(huì)根據(jù)
占屏比例,自動(dòng)計(jì)算轉(zhuǎn)換當(dāng)前屏幕下適配的大小。加載布局其實(shí)是把各自的
Layout都轉(zhuǎn)換為對(duì)應(yīng)的AutoLayout,從而不用在所有的xml中進(jìn)行更改。

思路很gay,但是也有一些弊端,在onMeasure的時(shí)候進(jìn)行數(shù)值計(jì)算,存在性能問(wèn)題
擴(kuò)展性差,用到的ViewGroup都需要自行對(duì)AutoLayout進(jìn)行擴(kuò)展。
最重要的是:

issues較多,而且作者不維護(hù),應(yīng)用到實(shí)際項(xiàng)目中還需自行權(quán)衡...


6.ConstraintLayout 約束布局

使用約束的方式來(lái)指定各個(gè)控件的位置和關(guān)系的,可以看做更加強(qiáng)大的
RelativeLayout,通過(guò)圖形化界面拖拽的方式來(lái)編寫(xiě)界面,當(dāng)然也可以
直接用XML進(jìn)行編寫(xiě),畢竟拖拽的背后也是XML來(lái)實(shí)現(xiàn)的,不過(guò)屬性比較
多,直接編寫(xiě)顯得有些繁瑣,建議還是拖拽后自己在手動(dòng)修改參數(shù)

ConstraintLayout約束布局除了支持百分比外,相比傳統(tǒng)布局一層
套一層的嵌套布局結(jié)構(gòu),編寫(xiě)的XML元素層次結(jié)構(gòu)更簡(jiǎn)單(一個(gè)外層
ConstraintLayout包全部),而且性能更優(yōu)。
至于問(wèn)題的話(huà),可能就是布局中的元素過(guò)于復(fù)雜時(shí),拖拽可能會(huì)有少許問(wèn)題;

其他的話(huà)暫時(shí)沒(méi)發(fā)現(xiàn),關(guān)于ConstraintLayout與傳統(tǒng)布局方式的性能對(duì)比可見(jiàn):
解析ConstraintLayout的性能優(yōu)勢(shì)

而關(guān)于圖形化拖拽的,郭霖大神有篇詳細(xì)講解的博文:
Android新特性介紹,ConstraintLayout完全解析

而關(guān)于屬性講解和具體實(shí)例的,可以翻看鴻洋的博文:
ConstraintLayout 完全解析 快來(lái)優(yōu)化你的布局吧

附:記下關(guān)鍵點(diǎn),方便自己日后回憶

  • Inspector:右側(cè)Properties區(qū)域的上半部分,豎直和水平的軸用于確定
    位置;圖中的四個(gè)16確定的是間距;中間的四個(gè) >>> 的箭頭確定的是大小
    有三種可選的模式:
    wrap_content、
    固定值、
    any size
    用于填充滿(mǎn)當(dāng)前控件的約束規(guī)則,和match_parent是不同的!

?

  • Guidelines:參照線(xiàn)
    ,就是弄個(gè)線(xiàn)給別的控件提供約束,有垂直和水平
    兩種,用來(lái)實(shí)現(xiàn)一些百分比的效果很贊,比如下圖這種兩個(gè)控件并排居中的布局:

    ?
  • 自動(dòng)添加約束:拖拽控件后,一個(gè)個(gè)去添加約束非常繁瑣,ConstraintLayout中
    支持自動(dòng)添加約束,有兩種自動(dòng)添加約束的方式:
    AutoConnect:默認(rèn)關(guān)閉,啟用后拖拉控件到布局里會(huì)自動(dòng)生成約束

    Infer Constraints:控件拖拉得差不多后,點(diǎn)擊后會(huì)為所有控件生成約束

    當(dāng)然,這兩種自動(dòng)生成的約束可能有些問(wèn)題,我們可以自己另外調(diào)整下~

7.等比例縮放的另一種實(shí)現(xiàn)方案

同樣是等比例縮放的套路,原文可見(jiàn):一種粗暴快速的Android全屏幕適配方案

上面也說(shuō)了AndroidAutoLayout在onMeasure中進(jìn)行數(shù)值運(yùn)算可能會(huì)有性能問(wèn)題。
而這個(gè)方案則是規(guī)避了這個(gè)問(wèn)題,直接在A(yíng)ndroid進(jìn)行長(zhǎng)度計(jì)算的時(shí)候就進(jìn)行換算;

系統(tǒng)長(zhǎng)度計(jì)算的入口是TypedValue里的applyDimension方法:

public static float applyDimension(int unit, float value, DisplayMetrics metrics){
    switch (unit) {
        case COMPLEX_UNIT_PX:
            return value;
        case COMPLEX_UNIT_DIP:
            return value * metrics.density;
        case COMPLEX_UNIT_SP:
            return value * metrics.scaledDensity;
        case COMPLEX_UNIT_PT:
            return value * metrics.xdpi * (1.0f/72);
        case COMPLEX_UNIT_IN:
            return value * metrics.xdpi;
        case COMPLEX_UNIT_MM:
            return value * metrics.xdpi * (1.0f/25.4f);
        }
        return 0;
    }
}

而作者選擇比較冷門(mén)的pt單位,從而避免對(duì)正常的px,dp,sp造成影響,
PT的計(jì)算為:value * metrics.xdpi * (1.0f/72),我們可以動(dòng)前面
metrics.xdpi,這個(gè)值應(yīng)改為:縮放比例7272的原因是想轉(zhuǎn)px,
metrics可以通過(guò)context.getResources().getDisplayMetrics()
拿到。作者另外寫(xiě)了一個(gè)Helper類(lèi),通過(guò)構(gòu)造方法傳入設(shè)計(jì)稿的寬度除以
當(dāng)前設(shè)備的分辨率得出比例,然后乘以72即可得出對(duì)應(yīng)分辨率下的尺寸。

調(diào)用也很簡(jiǎn)單,直接在A(yíng)pplication類(lèi)啟用即可:

new RudenessScreenHelper(this, 750).activate();

等比縮放套路換湯不換藥,不過(guò)很機(jī)智的規(guī)避了復(fù)雜的計(jì)算問(wèn)題,想法是挺贊的,
有興趣的可以試試。


小結(jié)


??????在本節(jié)中,筆者對(duì)于自己所知的Android原生適配套路都一一進(jìn)行了復(fù)述,相信會(huì)對(duì)
你在開(kāi)發(fā)中的屏幕適配有所幫助,當(dāng)然具體要怎么適配還是看需求吧,比如我在的
小作坊,也是只是適配720p,2333;當(dāng)然有其他的套路也歡迎告知,萬(wàn)分感激~
(PS:說(shuō)來(lái)慚愧,本來(lái)想著國(guó)慶能發(fā)的,后面因?yàn)楦鞣N瑣事拖到今天...)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容