Android今日頭條UI適配完善版

前言

眾所周知 android的碎片化一直困擾著開發(fā)者损痰,我們要花很多的時間去做UI適配的工作。主流的適配方案有兩種 1酒来、今日頭條適配 2卢未、smallestWidth適配。具體的實現(xiàn)點擊上述連接查看堰汉。

這里主要講的是今日頭條的適配方案辽社。他的邏輯很簡單,就是更具設(shè)計圖稿的寬度去動態(tài)的修改android運行設(shè)備DisplayMetrics的density翘鸭、scaledDensity滴铅、densityDpi。但是今日頭條只是貼出了示例代碼就乓。運行到正常開發(fā)的時候會遇到UI布局錯亂的問題汉匙。主要是因為app在運行過程屏幕旋轉(zhuǎn)、重力感應(yīng)生蚁、切換字體等因素導(dǎo)致onConfigurationChanged 改變導(dǎo)致的 DisplayMetrics的值被恢復(fù)噩翠。故在此基礎(chǔ)上做了修改保證運行中的穩(wěn)定性

原理

通過閱讀源碼,我們可以得知邦投,density 是 DisplayMetrics 中的成員變量伤锚,而 DisplayMetrics 實例通過 Resources#getDisplayMetrics 可以獲得,而Resources通過Activity或者Application的Context獲得志衣。我們只需要包裝Resources對象屯援,重寫其

getDisplayMetrics方法剂娄,修改其原始值

package com.xcheng.view.autosize;

import android.content.res.Resources;
import android.util.DisplayMetrics;

/**
 * 今日頭條的適配方案
 */
public class ResourcesWrapper extends Resources {
    private final AutoSize autoSize;
    private float targetDensity;
    private float targetScaledDensity;
    private int targetDensityDpi;

    public ResourcesWrapper(Resources resources, AutoSize autoSize) {
        super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration());
        this.autoSize = autoSize;
    }

    @Override
    public DisplayMetrics getDisplayMetrics() {
        DisplayMetrics displayMetrics = super.getDisplayMetrics();
        initValue(displayMetrics);
        autoSize(displayMetrics);
        return displayMetrics;
    }

    private void initValue(DisplayMetrics displayMetrics) {
        if (targetDensity == 0) {
            float nonCompatDensity = displayMetrics.density;
            float nonCompatScaledDensity = displayMetrics.scaledDensity;
            float designSizeInDp = autoSize.designSizeInDp;
            if (designSizeInDp > 0) {
                targetDensity = displayMetrics.widthPixels / designSizeInDp;
            } else {
                targetDensity = displayMetrics.heightPixels / -designSizeInDp;
            }
            targetScaledDensity = targetDensity * (nonCompatScaledDensity / nonCompatDensity);
            targetDensityDpi = (int) (160 * targetDensity);
        }
    }

    private void autoSize(DisplayMetrics displayMetrics) {
        displayMetrics.density = targetDensity;
        displayMetrics.densityDpi = targetDensityDpi;
        if (autoSize.isSupportSp) {
            displayMetrics.scaledDensity = targetScaledDensity;
        }
    }
}

AutoSize源碼

package com.xcheng.view.autosize;

/**
 * 創(chuàng)建時間:2018/11/12
 * 編寫人: chengxin
 * 功能描述:適配實體類
 */
public class AutoSize {
    /**
     * 默認(rèn)的設(shè)計尺寸
     * >0 設(shè)置寬度
     * <0 設(shè)置高度
     */
    public final float designSizeInDp;
    public final boolean isSupportSp;

    /**
     * @param designSizeInDp 設(shè)計寬度貨高度
     * @param isSupportSp    是否支持sp
     */
    public AutoSize(float designSizeInDp, boolean isSupportSp) {
        if (designSizeInDp == 0) {
            throw new IllegalArgumentException("designSizeInDp==0");
        }
        this.designSizeInDp = designSizeInDp;
        this.isSupportSp = isSupportSp;
    }
}

在Activity基類中重寫getResources方法

@Override
public Resources getResources() {
    if (mResources == null) {
        final AutoSize autoSize = getAutoSize();
        if (autoSize != null) {
            mResources = new ResourcesWrapper(super.getResources(), autoSize);
        }
    }
    return mResources != null ? mResources : super.getResources();
}

/**
 * 子類可重寫適配
 **/
@Nullable
protected AutoSize getAutoSize() {
    return EasyView.AUTOSIZE;
}

子類activiy根據(jù)需要重寫getAutoSize即可,如:
返回null表示不適配

@Nullable
@Override
protected AutoSize getAutoSize() {
    return new AutoSize(360/*設(shè)計的寬度dp*/, true);
}

核心代碼只有這么多玄呛,開發(fā)者根據(jù)需要提取即可。

tips:

1和二、該實現(xiàn)核心思想是通過攔截Resources#getDisplayMetrics()方法徘铝,讀者可根據(jù)其原理自動擴(kuò)展支持 PT、IN惯吕、MM惕它。
2、該適配思想最大的優(yōu)點是穩(wěn)定性废登,不會隨著onConfigurationChanged導(dǎo)致其值被恢復(fù)為原始值淹魄,因為每次調(diào)用Resources#getDisplayMetrics()都會重新賦值適配(僅為簡單的賦值,不會影響運行效率)堡距。

github地址:https://github.com/xchengDroid/EasyView
轉(zhuǎn)載請注明原文地址:http://www.reibang.com/p/41930fde7aac

推薦:

1甲锡、Android AutoBundle 自動裝箱和拆箱Bundle
2、Android超級好用的CheckView
3羽戒、Retrofit 最簡潔易用的封裝缤沦,優(yōu)雅的取消請求,不依賴任何第三方框架

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末易稠,一起剝皮案震驚了整個濱河市缸废,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驶社,老刑警劉巖企量,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亡电,居然都是意外死亡届巩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門逊抡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姆泻,“玉大人,你說我怎么就攤上這事冒嫡∧床” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵孝凌,是天一觀的道長方咆。 經(jīng)常有香客問我,道長蟀架,這世上最難降的妖魔是什么瓣赂? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任榆骚,我火速辦了婚禮,結(jié)果婚禮上煌集,老公的妹妹穿的比我還像新娘妓肢。我一直安慰自己,他們只是感情好苫纤,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布碉钠。 她就那樣靜靜地躺著,像睡著了一般卷拘。 火紅的嫁衣襯著肌膚如雪喊废。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天栗弟,我揣著相機(jī)與錄音污筷,去河邊找鬼。 笑死乍赫,一個胖子當(dāng)著我的面吹牛瓣蛀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雷厂,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼揪惦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了罗侯?” 一聲冷哼從身側(cè)響起器腋,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钩杰,沒想到半個月后纫塌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡讲弄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年措左,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片避除。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡怎披,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瓶摆,到底是詐尸還是另有隱情凉逛,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布群井,位于F島的核電站状飞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诬辈,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一酵使、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧焙糟,春花似錦口渔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至混巧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間勤揩,已是汗流浹背咧党。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留陨亡,地道東北人傍衡。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像负蠕,于是被迫代替她去往敵國和親蛙埂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354