Android 自定义控件基础-流式布局

   什么是流式布局?其实我们在平时遇到过,只是有可能叫不出它的名字。
  如图:


Android 自定义控件基础-流式布局_第1张图片

  如上图,就是一个流式布局的样式。
 &esmp;这里,将记录一下怎么实现这个功能。其实实现这个功能的方法,就是自定义ViewGroup。
  自定义ViewGroup的时候,要注意两点:

  1.子View和父View大小的测量。
  2.子View的在父View里面怎么摆放。

  想要解决上面的两个问题,就得重写两个方法,分别是:onMeasure方法,在这个方法我们通常来测量子View和父View的大小;onLayout方法,在这个方法里面,我们通常来决定子View在父View的摆放。

1.重写onMeasure方法

//测量父控件和子控件的大小
    @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.重写onLayou方法

private List> mAllViews = new ArrayList>();
    private List mLineHeights = new ArrayList();

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mAllViews.clear();
        mLineHeights.clear();
        int width = getWidth(); // 父布局的宽度
        List lineViews = new ArrayList();
        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();
                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的时候,一定要定义ViewGroup的LayoutParams。所以还要重写generateLayoutParams方法。

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

你可能感兴趣的:(Android 自定义控件基础-流式布局)