Android 自定義控件基礎(chǔ)-流式布局

?? 什么是流式布局?其實(shí)我們?cè)谄綍r(shí)遇到過(guò),只是有可能叫不出它的名字。
??如圖:



??如上圖,就是一個(gè)流式布局的樣式。
?&esmp;這里,將記錄一下怎么實(shí)現(xiàn)這個(gè)功能。其實(shí)實(shí)現(xiàn)這個(gè)功能的方法,就是自定義ViewGroup。
??自定義ViewGroup的時(shí)候,要注意兩點(diǎn):

??1.子View和父View大小的測(cè)量。
??2.子View的在父View里面怎么擺放。

??想要解決上面的兩個(gè)問(wèn)題,就得重寫(xiě)兩個(gè)方法,分別是:onMeasure方法,在這個(gè)方法我們通常來(lái)測(cè)量子View和父View的大?。籵nLayout方法,在這個(gè)方法里面,我們通常來(lái)決定子View在父View的擺放。

1.重寫(xiě)onMeasure方法

//測(cè)量父控件和子控件的大小
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int width = getMeasuredWidth();
        int height = 0;
        int lineWidth = 0;
        int lineHeight = 0;
        int childWidth = 0;
        int childHeight = 0;
        for (int i = 0, n = getChildCount(); i < n; i++) {
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);

            MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams();
            Log.i("main", "width = " + child.getMeasuredWidth() + " height = " + child.getMeasuredHeight() + " leftMargin = " + marginLayoutParams.leftMargin + " rightMargin = " + marginLayoutParams.rightMargin);
            childWidth = child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;
            childHeight = child.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin;
            //換行
            if (lineWidth + childWidth > width) {
                lineWidth = childWidth;
                height += lineHeight;
            } else {
                lineWidth += childWidth;
                lineHeight = Math.max(childHeight, lineHeight);
            }
            if (i == n - 1) {
                height += lineHeight;
            }
        }
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width, heightMode == MeasureSpec.EXACTLY ? heightSize : height);
    }

2.重寫(xiě)onLayou方法

private List<List<View>> mAllViews = new ArrayList<List<View>>();
    private List<Integer> mLineHeights = new ArrayList<Integer>();

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mAllViews.clear();
        mLineHeights.clear();
        int width = getWidth(); // 父布局的寬度
        List<View> lineViews = new ArrayList<View>();
        int childWidth = 0;
        int childHeight = 0;
        int lineWidth = 0;
        int lineHeight = 0;
        Log.i("main", "childCount = " + getChildCount() + " width = " + width);
        for (int i = 0, n = getChildCount(); i < n; i++) {
            View child = getChildAt(i);
            MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams();
            childWidth = child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;
            childHeight = child.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin;
            if (childWidth + lineWidth > width) {
                mAllViews.add(lineViews);
                mLineHeights.add(lineHeight);
                lineViews = new ArrayList<View>();
                lineWidth = 0;
                lineHeight = childHeight;

            }
            lineWidth += childWidth;
            lineHeight = Math.max(lineHeight, childHeight);
            lineViews.add(child);
        }
        mAllViews.add(lineViews);
        mLineHeights.add(lineHeight);
        int top = 0;
        int left = 0;
        Log.i("main", "n = " + mAllViews.size() + " m = " + lineViews.size());

        for(int i = 0, n = mAllViews.size(); i < n; i++)
        {
            lineViews = mAllViews.get(i);
            for(int j = 0, m = lineViews.size(); j < m; j++)
            {
                View child = lineViews.get(j);
                if(child.getVisibility() == View.GONE)
                {
                    continue;
                }
                MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams();
                int lc = left + marginLayoutParams.leftMargin;
                int tc = top + marginLayoutParams.topMargin;
                int rc = lc + child.getMeasuredWidth();
                int bc = tc + child.getMeasuredHeight();
                Log.i("main", "lc = " + lc + " tc = " + tc + " rc = " + rc + " bc = " + bc);
                child.layout(lc, tc, rc, bc);
                left += child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;
            }
            left = 0;
            top += mLineHeights.get(i);
        }
    }

??在自定義ViewGroup的時(shí)候,一定要定義ViewGroup的LayoutParams。所以還要重寫(xiě)generateLayoutParams方法。

@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
    return new MarginLayoutParams(getContext(), attrs);
}
?著作權(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)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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