Android自定义ViewGroup,实现自动换行

学习《Android开发艺术探索》中自定义ViewGroup章节

自定义ViewGroup总结的知识点

一.自定义ViewGroup中,onMeasure理解

   onMeasure(int widthMeasureSpec,int heightMeasureSpec); 需要进行补充的逻辑

   1.对布局设置为wrap_content的兼容,具体查看下一篇日志的构建MeasureSpec的方法

  最终实现是在onMeasure(...)方法中对LayoutParams设置为wrap_content的实现,在构建MeasureSpec时将,这个转换为MeasureSpec.AT_MOST这样的设置模式

注:下面模式一般适用于单View(不包括ViewGroup),因为ViewGroup设置为wrap_content时,是测量所有子View高/宽的和

单View

if(widthMode == MeasureSpec.AT_MOST && height == MeasureSpec.AT_MOST){
   setMeasureDimission(测量的宽,测量的高);
}else if(widthMode == MeasureSpec.AT_MOST ){
   setMeasureDimission(测量的宽,heightMeasureSpec);//heightMeasureSpec是父布局指定
}else if(heightMode == MeasureSpec.AT_MOST ){
   setMeasureDimission(widthMeasureSpec,测量的高);//widthMeasureSpec是父布局指定
}

ViewGroup(此方法在ViewGroup中已经实现,在自定义ViewGroup中可直接调用)

  /**
     * Utility to reconcile a desired size and state, with constraints imposed
     * by a MeasureSpec.  Will take the desired size, unless a different size
     * is imposed by the constraints.  The returned value is a compound integer,
     * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and
     * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the resulting
     * size is smaller than the size the view wants to be.
     *
     * @param size How big the view wants to be
     * @param measureSpec Constraints imposed by the parent
     * @return Size information bit mask as defined by
     * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
     */
    public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize =  MeasureSpec.getSize(measureSpec);
        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
            if (specSize < size) {
                result = specSize | MEASURED_STATE_TOO_SMALL;
            } else {
                result = size;
            }
            break;
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result | (childMeasuredState&MEASURED_STATE_MASK);
    }

  

2.onMeasure方法中参数的理解,widthMeasureSpec和heightMeasureSpec,在布局中去掉了margin参数后的值,将测量值通过setMeasureDimission设置该布局的宽和高

      理解如下图

      Android自定义ViewGroup,实现自动换行_第1张图片

      

   二,自定义ViewGroup中,onLayout的理解

       1.onLayout(boolean changed, int l, int t, int r, int b) 对方法中参数,changed为当前布局是否改变

          l,t,r,b是当前的布局的参数坐标,即有 当前控件宽度 width = r - l  高度 height = b - t;这里包括了padding的值

 注意:在自定义ViewGroup的时候,实际计算得到的宽高均需要加入padding的值和子布局的margin值,而onMeasure或onLayout方法中传递过来的值,均不包含padding的值,这里要减去

   总结:ViewGroup本身计算不用加入ViewGroup本身的margin,但要考虑padding变化,同时要考虑子View中margin的值

   以上方法均需要调用子布局的measure和layout方法

  例子: 自定义有自动换行功能的ViewGroup

package com.tongcheng.android.travel.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import com.tongcheng.android.R;


/**
 * Created by lcl11718 on 2016/12/6.
 * 横向实现自动换行的ViewGroup
 */

public class HorizontalWrapLineLayout extends ViewGroup {

    private int mVerticalSpace;
    private int mHorizontalSpace;

    public HorizontalWrapLineLayout(Context context) {
        this(context, null);
    }

    public HorizontalWrapLineLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        setAttributeSet(context, attrs);
    }

    /**
     * 设置自定义属性
     *
     * @param context
     * @param attrs
     */
    private void setAttributeSet(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HorizontalWrapLineLayout);
        //属性中定义左右边距 padding margin
        //属性中定义每一个距离垂直方向vertalSpace 和水平方向horizontalSpace
        mVerticalSpace = (int) a.getDimension(R.styleable.HorizontalWrapLineLayout_verticalWrapSpace, 0);
        mHorizontalSpace = (int) a.getDimension(R.styleable.HorizontalWrapLineLayout_horizontalWrapSpace, 0);
        a.recycle();
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

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

    @Override
    protected boolean checkLayoutParams(LayoutParams p) {
        return p instanceof MarginLayoutParams;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 这里的高度和宽度是去掉margin的值
        int horizontalPadding = getPaddingLeft() + getPaddingRight();
        int measureWidth = horizontalPadding;
        int verticalPadding = getPaddingTop() + getPaddingBottom();
        int measureHeight = verticalPadding;
        final int childCount = getChildCount();

        int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec);
        if (childCount == 0) {
            setMeasuredDimension(0, 0);
            return;
        }
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            //测量子View
            if (childView.getVisibility() != View.GONE) {
                measureChildWithMargins(childView, widthMeasureSpec, 0, heightMeasureSpec, 0);
                MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();
                int childMeasuredHeight = childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
                int childMeasuredWidth = childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                measureWidth += childMeasuredWidth + mHorizontalSpace;
                if (measureWidth > widthSpaceSize) {
                    measureHeight += childMeasuredHeight + mVerticalSpace;
                    measureWidth = getPaddingLeft() + getPaddingRight();
                }
                if (childCount - 1 == i && measureWidth > 0) {
                    measureHeight += childMeasuredHeight + mVerticalSpace;
                }
            }
        }
        if (heightSpaceMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthMeasureSpec, measureHeight);
        } else {
            setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
        }
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //这里的四角参数,是去掉Margin的参数
        int childCount = getChildCount();
        int left = getPaddingLeft();
        int top = getPaddingTop();
        int right = r - getPaddingRight();

        int currentLeft = left;
        int currentTop = top;
        int lineHeight = 0;
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();
            //确定4个点
            if (currentLeft + childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin >= right) {//换行
                currentLeft = left;
                currentTop += lineHeight + mVerticalSpace;
                lineHeight = childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            } else {
                lineHeight = Math.max(lineHeight, childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
            }
            childView.layout(
                    currentLeft + lp.leftMargin,
                    currentTop + lp.topMargin,
                    currentLeft + lp.leftMargin + childView.getMeasuredWidth(),
                    currentTop + lp.topMargin + childView.getMeasuredHeight());
            currentLeft += childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin + mHorizontalSpace;
        }
    }
}

  上个版本是简略的实现,下面是优化之后,这个版本支持Grivity布局

 

package com.tongcheng.android.travel.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.LayoutDirection;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;

import com.tongcheng.android.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by lcl11718 on 2016/12/8.
 * 自动换行容器
 */

public class AutoRowLayout extends ViewGroup {

    /**
     * 平均分配
     */
    public static final int AVERAGE = 0;
    /**
     * 自适应
     */
    public static final int ADAPTIVE = 1;
    /**
     * style
     */
    private int mStyleType;
    /**
     * 列之间间距
     */
    private int mColumnSpace;
    /**
     * 行之间间距
     */
    private int mRowSpace;
    /**
     * 列数量
     */
    private int mColumnNum;
    /**
     * 行数
     */
    private int mRowNum;

    /**
     * 最大行数
     */
    private int mMaxLine;
    /**
     * 对齐方式
     */
    private int mGravity = Gravity.START | Gravity.TOP;

    /**
     * 自适应测量算法 记录行数
     */
    private List mAdaptiveLines = new ArrayList();

    public AutoRowLayout(Context context) {
        this(context, null, 0);
    }

    public AutoRowLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoRowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setAttributes(context, attrs);
    }

    /**
     * set basic attrs
     *
     * @param context
     * @param attrs
     */
    public void setAttributes(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.AutoRowLayout);
        mStyleType = ta.getInt(R.styleable.AutoRowLayout_style_type, 0);//0 是平均分
        mColumnSpace = (int) ta.getDimension(R.styleable.AutoRowLayout_columnSpace, 0);
        mRowSpace = (int) ta.getDimension(R.styleable.AutoRowLayout_rowSpace, 0);
        mColumnNum = ta.getInt(R.styleable.AutoRowLayout_columnNum, 0);
        mRowNum = ta.getInt(R.styleable.AutoRowLayout_rowNum, 0);
        mMaxLine = ta.getInt(R.styleable.AutoRowLayout_maxLine, 0);
        mGravity = ta.getInt(R.styleable.AutoRowLayout_android_gravity, 0);
        ta.recycle();
    }

    /**
     * set style type
     *
     * @param type
     */
    public void setStyleType(int type) {
        this.mStyleType = type;
    }

    public void setColumnSpace(int columnSpace) {
        this.mColumnSpace = columnSpace;
    }

    public void setRowSpace(int rowSpace) {
        this.mRowSpace = rowSpace;
    }

    public void setColumnNum(int columnNum) {
        this.mColumnNum = columnNum;
    }

    public void setRowNum(int rowNum) {
        this.mRowNum = rowNum;
    }

    public void setGravity(int gravity) {
        this.mGravity = gravity;
    }


    /***********************************
     * 加入Margin start
     **************************************/
    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

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

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

    @Override
    protected boolean checkLayoutParams(LayoutParams p) {
        return p != null && p instanceof MarginLayoutParams;
    }

    /***********************************
     * 加入Margin end
     **************************************/


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mStyleType == AVERAGE) {
            measureAverage(widthMeasureSpec, heightMeasureSpec);
        } else if (mStyleType == ADAPTIVE) {
            measureAdaptive(widthMeasureSpec, heightMeasureSpec);
        }
    }

    /**
     * 平均测量算法
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    private void measureAverage(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();
        if (count == 0) {
            setMeasuredDimension(0, 0);
            return;
        }

        int widthPadding = getPaddingLeft() + getPaddingRight();
        int heightPadding = getPaddingTop() + getPaddingBottom();
        int childState = 0;
        // get a max child width for widthMeasureSpec
        int maxChildWidth = getMaxChildWidth(count, widthMeasureSpec, heightMeasureSpec, childState);
        int maxWidth = 0;

        if (mColumnNum > 0) {
            maxWidth = maxChildWidth * mColumnNum + (mColumnNum - 1) * mColumnSpace + widthPadding;
        } else {
            throw new RuntimeException("autoRowLayout must set a column num");
        }

        int widthMeasureSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);

        View firstChild = getChildAt(0);
        int totalRowNumHeight = mRowNum * firstChild.getMeasuredHeight() + (mRowNum - 1) * mRowSpace + heightPadding;
        int maxHeight = mRowNum > 0 ? totalRowNumHeight : getTotalHeightNoRows(count, heightPadding, firstChild);

        int limitMaxWidth = (widthMeasureSize - widthPadding - (mColumnNum - 1) * mColumnSpace) / mColumnNum;
        int maxAllowWidth = MeasureSpec.EXACTLY == widthMeasureMode ? limitMaxWidth : Math.min(maxChildWidth, limitMaxWidth);
        setWidthLayoutParams(count, maxAllowWidth);

        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
        int heightAndState = resolveSizeAndState(maxHeight, heightMeasureSpec, 0);
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), heightAndState);
    }

    /**
     * set per max width  of views
     *
     * @param count
     * @param maxChildWidth
     */
    private void setWidthLayoutParams(int count, int maxChildWidth) {
        for (int index = 0; index < count; index++) {
            View child = getChildAt(index);
            if (child.getVisibility() == View.GONE) {
                continue;
            }
            MarginLayoutParams lp = new MarginLayoutParams(maxChildWidth, child.getLayoutParams().height);
            child.setLayoutParams(lp);
        }
    }

    /**
     * get max height not set row num
     *
     * @param count
     * @param heightPadding
     * @param child
     * @return
     */
    private int getTotalHeightNoRows(int count, int heightPadding, View child) {

        int allowRowNums = count / mColumnNum;
        int maxHeight = allowRowNums * child.getMeasuredHeight() + (allowRowNums - 1) * mRowSpace + heightPadding;

        if (count % mColumnNum > 0) {
            maxHeight += child.getMeasuredHeight() + mRowSpace;
        }
        return maxHeight;
    }

    /**
     * get a max child width for this layout
     *
     * @param count
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     * @return
     */
    private int getMaxChildWidth(int count, int widthMeasureSpec, int heightMeasureSpec, int childState) {
        int maxChildWidth = 0;
        for (int index = 0; index < count; index++) {
            View child = getChildAt(index);
            if (child.getVisibility() == View.GONE) {
                continue;
            }
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            childState = combineMeasuredStates(childState, child.getMeasuredState());
            maxChildWidth = Math.max(maxChildWidth, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
        }
        return maxChildWidth;
    }


    /**
     * 自适应测量算法
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    private void measureAdaptive(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();
        if (count == 0) {
            setMeasuredDimension(0, 0);
            return;
        }
        int widthPadding = getPaddingLeft() + getPaddingRight();
        int heightPadding = getPaddingTop() + getPaddingBottom();
        int width = widthPadding;
        int height = heightPadding;
        int lineMaxHeight = 0;

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int childState = 0;
        mAdaptiveLines.clear();
        for (int index = 0; index < count; index++) {
            View child = getChildAt(index);
            if (child.getVisibility() == View.GONE) {
                continue;
            }
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            if (width + child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin > widthSize) {//换行
                height += lineMaxHeight + mRowSpace;
                width = widthPadding + child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin + mColumnSpace;
                lineMaxHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
                mAdaptiveLines.add(index);
            } else {
                lineMaxHeight = Math.max(lineMaxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
                width += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin + mColumnSpace;
                childState = combineMeasuredStates(childState, child.getMeasuredState());
            }
        }
        mAdaptiveLines.add(count);
        height += lineMaxHeight;

        height = Math.max(height, getSuggestedMinimumHeight());
        int heightAndState = resolveSizeAndState(height, heightMeasureSpec, 0);
        setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState), heightAndState);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (mStyleType == AVERAGE) {
            layoutAverage(l, t, r, b);
        } else if (mStyleType == ADAPTIVE) {
            layoutAdaptive(l, t, r, b);
        }
    }


    /**
     * 平均布局算法
     *
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    private void layoutAverage(int left, int top, int right, int bottom) {
        int count = getChildCount();
        if (count == 0) {
            return;
        }
        int childLeft;
        int childTop = 0;
        int lineMaxHeight = 0;

        int totalRowNum = count / mColumnNum + (count % mColumnNum == 0 ? 0 : 1);

        int maxRowNum = mRowNum > 0 ? mRowNum : totalRowNum;

        for (int rowNum = 0; rowNum < maxRowNum; rowNum++) {
            childLeft = getPaddingLeft();
            childTop += rowNum > 0 ? lineMaxHeight + mRowSpace : getPaddingTop();
            for (int columnNum = 0; columnNum < mColumnNum; columnNum++) {
                if (columnNum + mColumnNum * rowNum >= count) {
                    break;
                }
                View child = getChildAt(columnNum + mColumnNum * rowNum);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

                child.layout(
                        childLeft + lp.leftMargin,
                        childTop + lp.topMargin,
                        childLeft + lp.leftMargin + lp.width,
                        childTop + lp.topMargin + lp.height);
                childLeft += lp.width + lp.leftMargin + lp.rightMargin + mColumnSpace;
                lineMaxHeight = Math.max(lineMaxHeight, lp.height + lp.topMargin + lp.bottomMargin);
            }
        }
    }

    /**
     * 自适应布局算法
     *
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    private void layoutAdaptive(int left, int top, int right, int bottom) {
        int count = getChildCount();
        if (count == 0) {
            return;
        }
        int width = right - left;
        int childSpace = width - getPaddingLeft() - getPaddingRight();

        int limitLines = mMaxLine > 0 ? Math.min(mMaxLine, mAdaptiveLines.size()) : mAdaptiveLines.size();
        int[] childLefts = new int[limitLines];

        int totalChildHeight = 0;

        for (int rowIndex = 0; rowIndex < limitLines; rowIndex++) {
            int startRowIndex = rowIndex > 0 ? mAdaptiveLines.get(rowIndex - 1) : 0;
            int endRowIndex = mAdaptiveLines.get(rowIndex);
            int maxChildWidth = 0;
            int lineMaxHeight = 0;
            for (; startRowIndex < endRowIndex; startRowIndex++) {
                View child = getChildAt(startRowIndex);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                maxChildWidth += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                if (startRowIndex != endRowIndex - 1) {
                    maxChildWidth += mColumnSpace;
                }
                lineMaxHeight = Math.max(lineMaxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
            }
            totalChildHeight += lineMaxHeight;
            childLefts[rowIndex] = getChildLeft(childSpace - maxChildWidth);
        }

        int childTop = getChildTop(top, bottom, totalChildHeight);
        for (int rowIndex = 0; rowIndex < limitLines; rowIndex++) {
            int startRowIndex = rowIndex > 0 ? mAdaptiveLines.get(rowIndex - 1) : 0;
            int endRowIndex = mAdaptiveLines.get(rowIndex);
            int childLeft = childLefts[rowIndex];
            for (; startRowIndex < endRowIndex; startRowIndex++) {
                View child = getChildAt(startRowIndex);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                child.layout(
                        childLeft + lp.leftMargin,
                        childTop + lp.topMargin,
                        childLeft + lp.leftMargin + child.getMeasuredWidth(),
                        childTop + lp.topMargin + child.getMeasuredHeight());
                childLeft += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin + mColumnSpace;
            }

        }
    }

    /**
     * get top of child View
     *
     * @param top
     * @param bottom
     * @param totalChildHeight
     * @return
     */
    private int getChildTop(int top, int bottom, int totalChildHeight) {
        int childTop;
        final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
        switch (majorGravity) {
            case Gravity.BOTTOM:
                // mTotalLength contains the padding already
                childTop = getPaddingTop() + bottom - top - totalChildHeight;
                break;

            // mTotalLength contains the padding already
            case Gravity.CENTER_VERTICAL:
                childTop = getPaddingTop() + (bottom - top - totalChildHeight) / 2;
                break;

            case Gravity.TOP:
            default:
                childTop = getPaddingTop();
                break;
        }
        return childTop;
    }

    /**
     * get left value of row
     *
     * @param widthSpace
     * @return
     */
    private int getChildLeft(int widthSpace) {
        int childLeft;
        final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
        final int absoluteGravity = Gravity.getAbsoluteGravity(minorGravity, LayoutDirection.LTR);
        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
            case Gravity.CENTER_HORIZONTAL:
                childLeft = getPaddingLeft() + (widthSpace / 2);
                break;

            case Gravity.RIGHT:
                childLeft = getPaddingLeft() + widthSpace;
                break;

            case Gravity.LEFT:
            default:
                childLeft = getPaddingLeft();
                break;
        }
        return childLeft;
    }
}

  

 

转载于:https://www.cnblogs.com/ghhryr-lichl/p/6141223.html

你可能感兴趣的:(Android自定义ViewGroup,实现自动换行)