你該知道的Android屏幕適配新姿勢(shì)

前言

前段時(shí)間在掘金上看了一篇關(guān)于Android屏幕適配的新方案Android 屏幕適配從未如斯簡(jiǎn)單(8月10日最終更新版)以及一種極低成本的Android屏幕適配方式, 這。隙赁。垦藏。 不是和我的適配方案一個(gè)思路嗎,還是有一定的差別伞访。

真的是巧了掂骏,我們公司也是做資訊的,呃厚掷。弟灼。 和頭條好像。起初冒黑,我們的需求是改字體田绑,于是寫了這篇文章Android屏幕適配,該文章寫了適配相關(guān)知識(shí)點(diǎn)以及如何防止更改系統(tǒng)字體影響應(yīng)用ui

接著抡爹,產(chǎn)品需求來了掩驱,每臺(tái)機(jī)子的資訊頻道個(gè)數(shù)不一樣,邊距也有差別冬竟,1像素都不能差欧穴。。泵殴。由于項(xiàng)目中并沒有做屏幕適配涮帘,手動(dòng)一個(gè)個(gè)文件改過去?笑诅?涼涼??????

最后调缨,從適配字體的方案延伸出適配屏幕的方案

真的是我自己的方案,巧的是和頭條想一塊去了

之前沒條件驗(yàn)證方案吆你,現(xiàn)在頭條幫我驗(yàn)證同蜻,撿了個(gè)現(xiàn)成的??????

需了解的相關(guān)知識(shí)

  • 屏幕尺寸

指屏幕對(duì)角線的物理尺寸(inch),1英寸=2.54cm

  • 屏幕分辨率

指屏幕橫縱向像素點(diǎn)(px),例:1920x1080早处、2560x1440

  • 像素密度

每英寸的像素點(diǎn)(dpi)

  • 屏幕無關(guān)像素

指與屏幕像素點(diǎn)無關(guān)的表示單位(dp/dip),主要用于限定控件大小

  • 密度關(guān)系及其換算表
密度類型 分辨率 像素密度 像素密度范圍 換算(dp->px)
ldpi 320x240 120 0~120 1dp -> 0.75px
mdpi 480x320 160 120~160 1dp -> 1px
hpdi 800x480 240 160~240 1dp -> 1.5px
xhdpi 1280x720 320 240~320 1dp -> 2px
xxhdpi 1920x1080 480 320~480 1dp -> 3px
xxxhdpi 2560x1440 640 480~640 1dp -> 4px
  • 調(diào)整首選項(xiàng)中字體大小,density不會(huì)變化瘫析,scaledDensity跟隨字號(hào)變化砌梆。因此有特殊需求的情況默责,不讓應(yīng)用字體跟隨設(shè)置中字號(hào)變化,可直接調(diào)整scaledDensity的值咸包。
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Resources.getSystem().getDisplayMetrics().scaledDensity = Resources.getSystem().getDisplayMetrics().density;
        getResources().getDisplayMetrics().scaledDensity = getResources().getDisplayMetrics().density;
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Resources.getSystem().getDisplayMetrics().scaledDensity = Resources.getSystem().getDisplayMetrics().density;
        getResources().getDisplayMetrics().scaledDensity = getResources().getDisplayMetrics().density;
    }
}

為什么需要屏幕適配桃序??烂瘫?

  • 之前媒熊,一直不懂為什么需要做適配?坟比?芦鳍? 使用dp不是能解決?葛账?柠衅? 1dp = (像素密度/160)px
  1. 先看像素密度公式:dpi = Math.sqrt(寬 * 寬 + 高 * 高) / 屏幕尺寸,其中寬高指的是屏幕分辨率的寬高

例子1:
小米4W
分辨率: 1080 * 1920
屏幕尺寸: 5inch
像素密度: dpi = Math.sqrt(1080 * 1080 + 1920 * 1920) / 5 ≈ 440
1dp = (440 / 160) ≈ 2.75px

例子2:
紅米Note4
分辨率: 1080 * 1920
屏幕尺寸: 5.5inch
像素密度: dpi = Math.sqrt(1080 * 1080 + 1920 * 1920) / 5.5 ≈ 400
1dp = (400 / 160) ≈ 2.5px

結(jié)論: 使用dp并不能完全解決屏幕適配問題籍琳,使用同樣的dp值在每個(gè)屏幕上展現(xiàn)出來的相對(duì)大小不一致

適配方案一(重新設(shè)置density)

dp與px怎么換算的菲宴?sp與px怎么換算的置鼻?

分析applyDimension

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 22, getResources().getDisplayMetrics());

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;
}

結(jié)論:
dp->px公式:value * metrics.density
sp->px公式:value * metrics.scaledDensity
因此關(guān)鍵在于metrics對(duì)象俩功,而metrics對(duì)象又是從Resources獲取到,Resources對(duì)象又是從Activity或者Application中獲取

分析DisplayMetrics對(duì)象

DisplayMetrics#density 用于dp與px的換算
DisplayMetrics#densityDpi 像素密度
DisplayMetrics#scaledDensity 字體的縮放因子剑梳,正常情況下和density相等呜达,但是調(diào)節(jié)系統(tǒng)字體大小后會(huì)改變這個(gè)值

嘗試修改Activity.getResources().getDisplayMetrics()屬性值谣蠢,以適配屏幕

放在setContentView之前

DisplayMetrics displayMetrics = app.getResources().getDisplayMetrics();
displayMetrics.densityDpi = 160;
displayMetrics.density = 1.0;
displayMetrics.scaledDensity = 1.0;

結(jié)論: 調(diào)整參數(shù)生效,具體分析可見頭條文章我就不在分析了一種極低成本的Android屏幕適配方式

densityDpi闻丑、density漩怎、scaledDensity要設(shè)置多少?

根據(jù)密度關(guān)系及其換算表嗦嗡,得知某個(gè)像素密度范圍會(huì)對(duì)應(yīng)一個(gè)標(biāo)準(zhǔn)值勋锤,因此我們直接根據(jù)標(biāo)準(zhǔn)值來設(shè)置這三個(gè)屬性值。這樣的好處是侥祭,將所有屏幕轉(zhuǎn)換成標(biāo)準(zhǔn)屏幕處理
例如: 小米4W 像素密度440 此時(shí)叁执,調(diào)整屬性值densityDpi = 480;density = 3.0; scaledDensity = 3.0;

實(shí)現(xiàn)代碼:
    /**
     * 獲取像素密度
     * @param densityDpi    像素密度
     */
    private static Density getDensity(int densityDpi) {
        if (densityDpi <= Density.LDPI.densityDpi) {
            return Density.LDPI;
        } else if (densityDpi <= Density.MDPI.densityDpi) {
            return Density.MDPI;
        } else if (densityDpi <= Density.HDPI.densityDpi) {
            return Density.HDPI;
        } else if (densityDpi <= Density.XHDPI.densityDpi) {
            return Density.XHDPI;
        } else if (densityDpi <= Density.XXHDPI.densityDpi) {
            return Density.XXHDPI;
        } else if (densityDpi <= Density.XXXHDPI.densityDpi) {
            return Density.XXXHDPI;
        } else {    // 其他情況使用默認(rèn)屏幕信息
            int density = (int) (1.0 * densityDpi / 160);
            if (density * 160 < densityDpi) {
                density += 1;
            }

            Density.WHATHDPI.setDensityDpi(density * 160);
            Density.WHATHDPI.setDensity(density);
            Density.WHATHDPI.setScaledDensity(density);
            Density.WHATHDPI.setScaledDensity(density);
            return Density.WHATHDPI;
        }
    }
修改系統(tǒng)字體大小返回頁面后是否影響配置

修改后會(huì)影響頁面配置矮冬,需實(shí)現(xiàn)Activity#onConfigurationChanged或Application#onConfigurationChanged方法谈宛,重新設(shè)置配置

    @Override
    public void onConfigurationChanged(android.content.res.Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        AdaptiveUtil.resetDensity(this);
    }
更改全局的參數(shù)還是更改activity的參數(shù)

如果為了兼容以前版本,建議放在BaseActivity中處理配置調(diào)整; 否則在Application中處理統(tǒng)一更改配置

和頭條相比

① 頭條使用displayMetrics.widthPixels / 360來定義標(biāo)準(zhǔn)胎署,本文根據(jù)原始的像素密度來匹配標(biāo)準(zhǔn)的屏幕
② 頭條不僅更改了Activity中的DisplayMetrics對(duì)象屬性吆录,還改了Appplication中的,本文少了Application中的更改琼牧,哎恢筝,我想的還是不夠細(xì)
③ 和今日頭條一樣哀卫,不受ui設(shè)計(jì)稿影響,如果設(shè)計(jì)稿是按照xxhdpi設(shè)計(jì)的撬槽,此時(shí)按照2px = 1dp完成布局此改,哪天設(shè)計(jì)稿換成xxxhdpi來設(shè)計(jì),此時(shí)按照3px = 1dp來完成布局即可侄柔。

遇到的問題和不足

冷啟動(dòng)圖使用layer時(shí)共啃,調(diào)整配置后應(yīng)用冷啟動(dòng)背景圖在部分機(jī)子上存在閃動(dòng)的情況,即因?yàn)闆]調(diào)配置前與調(diào)整配置后dp值變化導(dǎo)致圖片變大或縮小

適配方案二(最小寬度限定符)

  • 最小寬度限定符適配方案暂题,參考Android 目前穩(wěn)定高效的UI適配方案
  • 個(gè)人覺得弊病有三:① 根據(jù)該文章講解移剪,多個(gè)dimens文件會(huì)導(dǎo)致包增大,可能會(huì)增大300kb-800kb左右敢靡,可以接受吧挂滓;② 需要開發(fā)者有一定的經(jīng)驗(yàn),知道需要增加哪些常用的尺寸啸胧,避免無用功赶站;③ 即使有經(jīng)驗(yàn)的開發(fā)者也可能遺漏某個(gè)機(jī)型的適配;

Demo

demo鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纺念,一起剝皮案震驚了整個(gè)濱河市贝椿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌陷谱,老刑警劉巖烙博,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異烟逊,居然都是意外死亡渣窜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門宪躯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乔宿,“玉大人,你說我怎么就攤上這事访雪∠耆穑” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵臣缀,是天一觀的道長(zhǎng)坝橡。 經(jīng)常有香客問我,道長(zhǎng)精置,這世上最難降的妖魔是什么计寇? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上番宁,老公的妹妹穿的比我還像新娘蹲堂。我一直安慰自己,他們只是感情好贝淤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著政供,像睡著了一般播聪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上布隔,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天离陶,我揣著相機(jī)與錄音,去河邊找鬼衅檀。 笑死招刨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哀军。 我是一名探鬼主播沉眶,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼杉适!你這毒婦竟也來了谎倔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤猿推,失蹤者是張志新(化名)和其女友劉穎片习,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹬叭,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡藕咏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秽五。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孽查。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖筝蚕,靈堂內(nèi)的尸體忽然破棺而出卦碾,到底是詐尸還是另有隱情,我是刑警寧澤起宽,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布洲胖,位于F島的核電站,受9級(jí)特大地震影響坯沪,放射性物質(zhì)發(fā)生泄漏绿映。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叉弦。 院中可真熱鬧丐一,春花似錦、人聲如沸淹冰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽樱拴。三九已至柠衍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晶乔,已是汗流浹背珍坊。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留正罢,地道東北人阵漏。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像翻具,于是被迫代替她去往敵國和親履怯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容