鴻洋AutoLayout代碼分析(四):剩下的類


整體過一下認(rèn)識的類

除去attr包以外卓囚,我們一起看下哪些我們說過

Paste_Image.png

我們一起回顧下

  • 入口是 AutoLayoutActivity
    • 簡單處理奶镶,把
LinearLayout -> AutoLinearLayout
RelativeLayout -> AutoRelativeLayout
FrameLayout -> AutoFrameLayout
  • AutoLinearLayout,AutoRelativeLayout洛勉,AutoFrameLayout簡單實現(xiàn)

    • 通過 關(guān)聯(lián)和依賴 AutoLayoutHelper, 來連接
    • AutoLayoutInfo對象
    • (自己的靜態(tài)內(nèi)部類LayoutParams中 通過AutoLayoutHelper實現(xiàn)返回)
  • 獲取Manifest中信息AutoLayoutConifg

    • 通過依賴 PackageManager, ApplicationInfo獲取 design的寬高
    • 通過 ScreenUtils 來獲取屏幕寬高

其他類

除去attr包以外盯捌,哪些還沒有用過

Paste_Image.png
  • L
public class L
{
    public static boolean debug = false;
    private static final String TAG = "AUTO_LAYOUT";

    public static void e(String msg)
    {
        if (debug)
        {
            Log.e(TAG, msg);
        }
    }
}
  • 可以發(fā)現(xiàn),只是一個打印控制類

  • UseLandscape

public interface UseLandscape
{
}
  • 只是空的蘑秽,可能是預(yù)留以后寫的吧
  • AutoUtils
public class AutoUtils{
    public static void auto(View view)
    {
        autoSize(view);
        autoPadding(view);
        autoMargin(view);
    }

    public static void autoMargin(View view)
    {
        if (!(view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams))
            return;

        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        if (lp == null) return;

        Object tag = view.getTag(R.id.id_tag_autolayout_margin);
        if (tag != null) return;
        view.setTag(R.id.id_tag_autolayout_margin, "Just Identify");

        lp.leftMargin = getPercentWidthSize(lp.leftMargin);
        lp.topMargin = getPercentHeightSize(lp.topMargin);
        lp.rightMargin = getPercentWidthSize(lp.rightMargin);
        lp.bottomMargin = getPercentHeightSize(lp.bottomMargin);

    }

    public static void autoPadding(View view)
    {
        Object tag = view.getTag(R.id.id_tag_autolayout_padding);
        if (tag != null) return;
        view.setTag(R.id.id_tag_autolayout_padding, "Just Identify");

        int l = view.getPaddingLeft();
        int t = view.getPaddingTop();
        int r = view.getPaddingRight();
        int b = view.getPaddingBottom();

        l = getPercentWidthSize(l);
        t = getPercentHeightSize(t);
        r = getPercentWidthSize(r);
        b = getPercentHeightSize(b);

        view.setPadding(l, t, r, b);
    }

    public static void autoSize(View view)
    {
        ViewGroup.LayoutParams lp = view.getLayoutParams();

        if (lp == null) return;

        Object tag = view.getTag(R.id.id_tag_autolayout_size);
        if (tag != null) return;

        view.setTag(R.id.id_tag_autolayout_size, "Just Identify");

        if (lp.width > 0)
        {
            int screenWidth = AutoLayoutConifg.getInstance().getScreenWidth();
            int designWidth = AutoLayoutConifg.getInstance().getDesignWidth();
            lp.width = (int) (lp.width * 1.0f / designWidth * screenWidth);
        }

        if (lp.height > 0)
        {
            int screenHeight = AutoLayoutConifg.getInstance().getScreenHeight();
            int designHeight = AutoLayoutConifg.getInstance().getDesignHeight();
            lp.height = (int) (lp.height * 1.0f / designHeight * screenHeight);
        }
    }

    public static int getPercentWidthSize(int val)
    {
        int screenWidth = AutoLayoutConifg.getInstance().getScreenWidth();
        int designWidth = AutoLayoutConifg.getInstance().getDesignWidth();

        return (int) (val * 1.0f / designWidth * screenWidth);
    }

    public static int getPercentWidthSizeBigger(int val)
    {
        int screenWidth = AutoLayoutConifg.getInstance().getScreenWidth();
        int designWidth = AutoLayoutConifg.getInstance().getDesignWidth();

        int res = val * screenWidth;
        if (res % designWidth == 0)
        {
            return res / designWidth;
        } else
        {
            return res / designWidth + 1;
        }

    }

    public static int getPercentHeightSizeBigger(int val)
    {
        int screenHeight = AutoLayoutConifg.getInstance().getScreenHeight();
        int designHeight = AutoLayoutConifg.getInstance().getDesignHeight();

        int res = val * screenHeight;
        if (res % designHeight == 0)
        {
            return res / designHeight;
        } else
        {
            return res / designHeight + 1;
        }
    }

    public static int getPercentHeightSize(int val)
    {
        int screenHeight = AutoLayoutConifg.getInstance().getScreenHeight();
        int designHeight = AutoLayoutConifg.getInstance().getDesignHeight();

        return (int) (val * 1.0f / designHeight * screenHeight);
    }
}

我們發(fā)現(xiàn)都是靜態(tài)方法饺著,應(yīng)該就只是一個幫助類了

  • MetroLayout
public class MetroLayout extends ViewGroup
{

    private final AutoLayoutHelper mHelper = new AutoLayoutHelper(this);

    private static class MetroBlock
    {
        int left;
        int top;
        int width;
    }

    private List<MetroBlock> mAvailablePos = new ArrayList<>();
    private int mDivider;

    public MetroLayout(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MetroLayout);
        mDivider = a.getDimensionPixelOffset(R.styleable.MetroLayout_metro_divider, 0);
        mDivider = AutoUtils.getPercentWidthSizeBigger(mDivider);
        a.recycle();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {

        if (true)
            randomColor();

        if (!isInEditMode())
            mHelper.adjustChildren();

        measureChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

    private void randomColor()
    {
        Random r = new Random(255);

        for (int i = 0, n = getChildCount(); i < n; i++)
        {
            View v = getChildAt(i);

            v.setBackgroundColor(Color.argb(100, r.nextInt(), r.nextInt(), r.nextInt()));
        }
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {

        initAvailablePosition();

        int left = 0;
        int top = 0;
        int divider = mDivider;

        for (int i = 0, n = getChildCount(); i < n; i++)
        {
            View v = getChildAt(i);
            if (v.getVisibility() == View.GONE) continue;

            MetroBlock newPos = findAvailablePos(v);
            left = newPos.left;
            top = newPos.top;

            int childWidth = v.getMeasuredWidth();
            int childHeight = v.getMeasuredHeight();

            int right = left + childWidth;
            int bottom = top + childHeight;

            v.layout(left, top, right, bottom);

            if (childWidth + divider < newPos.width)
            {
                newPos.left += childWidth + divider;
                newPos.width -= childWidth + divider;
            } else
            {
                mAvailablePos.remove(newPos);
            }

            MetroBlock p = new MetroBlock();
            p.left = left;
            p.top = bottom + divider;
            p.width = childWidth;
            mAvailablePos.add(p);

            mergeAvailablePosition();

        }
    }

    private void mergeAvailablePosition()
    {
        if (mAvailablePos.size() <= 1) return;

        List<MetroBlock> needRemoveBlocks = new ArrayList<>();

        MetroBlock one = mAvailablePos.get(0);
        MetroBlock two = mAvailablePos.get(1);

        for (int i = 1, n = mAvailablePos.size(); i < n - 1; i++)
        {
            if (one.top == two.top)
            {
                one.width = one.width + two.width;
                needRemoveBlocks.add(one);
                two.left = one.left;
                two = mAvailablePos.get(i + 1);
            } else
            {
                one = mAvailablePos.get(i);
                two = mAvailablePos.get(i + 1);
            }
        }

        mAvailablePos.removeAll(needRemoveBlocks);

    }

    private void initAvailablePosition()
    {
        mAvailablePos.clear();
        MetroBlock first = new MetroBlock();
        first.left = getPaddingLeft();
        first.top = getPaddingTop();
        first.width = getMeasuredWidth();
        mAvailablePos.add(first);
    }

    private MetroBlock findAvailablePos(View view)
    {
        MetroBlock p = new MetroBlock();
        if (mAvailablePos.size() == 0)
        {
            p.left = getPaddingLeft();
            p.top = getPaddingTop();
            p.width = getMeasuredWidth();
            return p;
        }
        int min = mAvailablePos.get(0).top;
        MetroBlock minHeightPos = mAvailablePos.get(0);
        for (MetroBlock _p : mAvailablePos)
        {
            if (_p.top < min)
            {
                min = _p.top;
                minHeightPos = _p;
            }
        }
        return minHeightPos;
    }


    @Override
    public MetroLayout.LayoutParams generateLayoutParams(AttributeSet attrs)
    {
        return new LayoutParams(getContext(), attrs);
    }

    public static class LayoutParams extends ViewGroup.MarginLayoutParams
            implements AutoLayoutHelper.AutoLayoutParams
    {
        private AutoLayoutInfo mAutoLayoutInfo;

        public LayoutParams(Context c, AttributeSet attrs)
        {
            super(c, attrs);
            mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);
        }

        public LayoutParams(int width, int height)
        {
            super(width, height);
        }

        public LayoutParams(ViewGroup.LayoutParams source)
        {
            super(source);
        }

        public LayoutParams(MarginLayoutParams source)
        {
            super(source);
        }

        public LayoutParams(LayoutParams source)
        {
            this((ViewGroup.LayoutParams) source);
            mAutoLayoutInfo = source.mAutoLayoutInfo;
        }

        @Override
        public AutoLayoutInfo getAutoLayoutInfo()
        {
            return mAutoLayoutInfo;
        }


    }

}

也和前面的AutoXXXLayout類似箫攀,
都只是通過 關(guān)聯(lián)和依賴 AutoLayoutHelper ,
Override對應(yīng)的
onMeasure(int widthMeasureSpec, int heightMeasureSpec) 和 generateLayoutParams(AttributeSet attrs)
通過靜態(tài)內(nèi)部類 的接口幼衰, 傳遞 AutoLayoutHelper的實現(xiàn)
返回 AutoLayoutInfo 對象
這里沒有使用靴跛,所以暫時不考慮

  • AutoLayoutHelper
    • 這里就是 AutoLayoutHelper 最復(fù)雜
    • 很多類都會 關(guān)聯(lián) 和 依賴 它
    • 后面單獨分析這個類

AutoLayoutHelper

這里比較復(fù)雜,

Paste_Image.png

我們分別看一下這里面的接口和方法

AutoLayoutParams
public interface AutoLayoutParams
{
    AutoLayoutInfo getAutoLayoutInfo();
}

上一篇我們看到對應(yīng)的幾種AutoXXXLayout渡嚣,靜態(tài)內(nèi)部類LayoutParams梢睛,都會實現(xiàn)這個接口
對應(yīng)的實現(xiàn),就是 靜態(tài)方法 getAutoLayoutInfo(Context context,AttributeSet attrs)

AutoLayoutHelper構(gòu)造 和 initAutoLayoutConfig
    private static AutoLayoutConifg mAutoLayoutConifg;

    public AutoLayoutHelper(ViewGroup host)
    {
        mHost = host;

        if (mAutoLayoutConifg == null)
        {
            initAutoLayoutConfig(host);
        }

    }

    private void initAutoLayoutConfig(ViewGroup host)
    {
        mAutoLayoutConifg = AutoLayoutConifg.getInstance();
        mAutoLayoutConifg.init(host.getContext());
    }

這里识椰,可以發(fā)現(xiàn)绝葡,構(gòu)造只是
傳遞ViewGroup對象,

調(diào)用initAutoLayoutConfig方法裤唠,初始化 懶漢單例的AutoLayoutConifg對象


剩下的 2個前面用到的方法

在AutoXXXLayout中
都只是通過 關(guān)聯(lián)和依賴 這里的AutoLayoutHelper
onMeasure(int widthMeasureSpec, int heightMeasureSpec) 中
用到了 mHelper.adjustChildren()

generateLayoutParams(AttributeSet attrs)中
調(diào)用的靜態(tài)內(nèi)部類挤牛,接口的實現(xiàn),其實是構(gòu)造中
mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs) 實現(xiàn)的
這里种蘸,我們分別看下這2個方法

getAutoLayoutInfo(Context context,AttributeSet attrs)
    public static AutoLayoutInfo getAutoLayoutInfo(Context context,AttributeSet attrs)
    {

        AutoLayoutInfo info = new AutoLayoutInfo();

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoLayout_Layout);
        int baseWidth = a.getInt(R.styleable.AutoLayout_Layout_layout_auto_basewidth, 0);
        int baseHeight = a.getInt(R.styleable.AutoLayout_Layout_layout_auto_baseheight, 0);
        a.recycle();

        TypedArray array = context.obtainStyledAttributes(attrs, LL);

        int n = array.getIndexCount();


        for (int i = 0; i < n; i++)
        {
            int index = array.getIndex(i);
//            String val = array.getString(index);
//            if (!isPxVal(val)) continue;

            if (!isPxVal(array.peekValue(index))) continue;

            int pxVal = 0;
            try
            {
                pxVal = array.getDimensionPixelOffset(index, 0);
            } catch (Exception ignore)//not dimension
            {
                continue;
            }
            switch (index)
            {
                case INDEX_TEXT_SIZE:
                    info.addAttr(new TextSizeAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_PADDING:
                    info.addAttr(new PaddingAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_PADDING_LEFT:
                    info.addAttr(new PaddingLeftAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_PADDING_TOP:
                    info.addAttr(new PaddingTopAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_PADDING_RIGHT:
                    info.addAttr(new PaddingRightAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_PADDING_BOTTOM:
                    info.addAttr(new PaddingBottomAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_WIDTH:
                    info.addAttr(new WidthAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_HEIGHT:
                    info.addAttr(new HeightAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MARGIN:
                    info.addAttr(new MarginAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MARGIN_LEFT:
                    info.addAttr(new MarginLeftAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MARGIN_TOP:
                    info.addAttr(new MarginTopAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MARGIN_RIGHT:
                    info.addAttr(new MarginRightAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MARGIN_BOTTOM:
                    info.addAttr(new MarginBottomAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MAX_WIDTH:
                    info.addAttr(new MaxWidthAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MAX_HEIGHT:
                    info.addAttr(new MaxHeightAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MIN_WIDTH:
                    info.addAttr(new MinWidthAttr(pxVal, baseWidth, baseHeight));
                    break;
                case INDEX_MIN_HEIGHT:
                    info.addAttr(new MinHeightAttr(pxVal, baseWidth, baseHeight));
                    break;
            }
        }
        array.recycle();
        L.e(" getAutoLayoutInfo " + info.toString());
        return info;
    }

這里類中定義了很多靜態(tài)的int值墓赴,用于switch,
也有定義的LL靜態(tài)數(shù)組航瞭,對應(yīng)android中常用的屬性

Paste_Image.png

這里獲得這些常用屬性以后诫硕,for循環(huán)會通過int的靜態(tài)值,switch對應(yīng)的地方
在添加到 容器類 AutoLayoutInfo 的對象中
(也就是 前面提到的接口實現(xiàn)返回的 AutoLayoutInfo 對象)
這里刊侯,每個switch章办,對應(yīng)的一個 Attr 屬性類, 存放在 attr 包中(之前分析單獨忽略的那個package)
具體邏輯滨彻,之后再一起分析

adjustChildren()
public void adjustChildren()
{
    AutoLayoutConifg.getInstance().checkParams();

    for (int i = 0, n = mHost.getChildCount(); i < n; i++)
    {
        View view = mHost.getChildAt(i);
        ViewGroup.LayoutParams params = view.getLayoutParams();

        if (params instanceof AutoLayoutParams)
        {
            AutoLayoutInfo info =
                    ((AutoLayoutParams) params).getAutoLayoutInfo();
            if (info != null)
            {
                info.fillAttrs(view);
            }
        }
    }
}

這個類藕届,相對于上一個方法,簡單一點
這里會得到對應(yīng)ViewGroup的 子View 個數(shù)亭饵,
for循環(huán)獲取每個 子View的 LayoutParams
如果 params instanceof AutoLayoutParams
也就是說休偶, 是我們前面實現(xiàn)的 接口類型的時候
轉(zhuǎn)型獲取前面接口實現(xiàn)的 AutoLayoutInfo 對象
(就是 上一個 getAutoLayoutInfo(Context context,AttributeSet attrs) 返回的對象)
最后 遍歷 每個子View的 AutoLayoutInfo中每個常用屬性


下一篇我們可以了解鴻洋AutoLayout代碼分析(五):Attr相關(guān)類

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辜羊,隨后出現(xiàn)的幾起案子踏兜,更是在濱河造成了極大的恐慌,老刑警劉巖八秃,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碱妆,死亡現(xiàn)場離奇詭異,居然都是意外死亡昔驱,警方通過查閱死者的電腦和手機疹尾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人航棱,你說我怎么就攤上這事睡雇。” “怎么了饮醇?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵它抱,是天一觀的道長。 經(jīng)常有香客問我朴艰,道長观蓄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任祠墅,我火速辦了婚禮侮穿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毁嗦。我一直安慰自己亲茅,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布狗准。 她就那樣靜靜地躺著克锣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腔长。 梳的紋絲不亂的頭發(fā)上袭祟,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機與錄音捞附,去河邊找鬼巾乳。 笑死,一個胖子當(dāng)著我的面吹牛鸟召,可吹牛的內(nèi)容都是我干的胆绊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼欧募,長吁一口氣:“原來是場噩夢啊……” “哼压状!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起槽片,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肢础,沒想到半個月后还栓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡传轰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年剩盒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慨蛙。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡辽聊,死狀恐怖纪挎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情跟匆,我是刑警寧澤异袄,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站玛臂,受9級特大地震影響烤蜕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜迹冤,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一讽营、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泡徙,春花似錦橱鹏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至庶橱,卻和暖如春贮勃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苏章。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工寂嘉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枫绅。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓泉孩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親并淋。 傳聞我的和親對象是個殘疾皇子寓搬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

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

  • 回顧 上一節(jié),我們分析了很多類县耽,其中句喷,最重要的是 AutoLayoutHelper 類的2個方法adjustChi...
    dodo_lihao閱讀 815評論 0 0
  • AutoLayoutActivity AutoLayoutActivity 我們可以發(fā)現(xiàn),只是做了name的判斷兔毙,...
    dodo_lihao閱讀 1,857評論 2 3
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法唾琼,類相關(guān)的語法,內(nèi)部類的語法澎剥,繼承相關(guān)的語法锡溯,異常的語法,線程的語...
    子非魚_t_閱讀 31,643評論 18 399
  • Android提供了一種非常靈活的資源系統(tǒng),可以根據(jù)不同的條件提供可替代資源祭饭。因此芜茵,系統(tǒng)基于很少的改造就能支持新特...
    Gooooood閱讀 12,788評論 5 25
  • 我曾有一顆心,也有一個夢倡蝙。 夢想能像種子那樣長成參天大樹九串; 或極目遠(yuǎn)眺,能鋪路搭橋悠咱; 我曾有一顆心蒸辆,也有一個夢。 ...
    南蔻閱讀 144評論 0 2