自定义流式布局

public class MyFlowView extends ViewGroup {
    public MyFlowView(Context context) {
        this(context,null);
    }
    public MyFlowView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }
    public MyFlowView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    //测量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //总的宽度和高度
        int width=0;
        int height=0;
        //记录每一行的宽度和高度
        int lineWidth=0;
        int lineHeight=0;
        //宽度相关
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        //高度相关
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        for (int i=0;i<getChildCount();i++){
            View childAt = getChildAt(i);
            //测量子view的宽和高
            measureChild(childAt,widthMeasureSpec,heightMeasureSpec);
            //得到LayoutParms
            MarginLayoutParams lp= (MarginLayoutParams) childAt.getLayoutParams();
            //得到子view的宽度和高度
            int childWidth = childAt.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;
            int childHeight = childAt.getMeasuredHeight()+lp.topMargin+lp.bottomMargin;
            //换行
            if(lineWidth+childWidth>sizeWidth-getPaddingLeft()-getPaddingRight()){
                //对比得到最大宽度
                width=Math.max(width,lineWidth);
                //重置行宽
                lineWidth=childWidth;
                //累加高度
                height+=lineHeight;
                //重置行高
                lineHeight=childHeight;
            }else{
                //叠加行宽
                lineWidth+=childWidth;
                //得到最大行高
                lineHeight=Math.max(lineHeight,childHeight);
            }
            if(i==getChildCount()-1){
                width=Math.max(width,lineWidth);
                height+=lineHeight;
            }
        }
        switch (modeWidth){
            case MeasureSpec.EXACTLY:
                    width=sizeWidth;
                    break;
            case MeasureSpec.AT_MOST:
                    width+=getPaddingLeft()+getPaddingRight();
                    break;
            case MeasureSpec.UNSPECIFIED:
                    break;
        }
        switch (modeHeight){
            case MeasureSpec.EXACTLY:
                height=sizeHeight;
                break;
            case MeasureSpec.AT_MOST:
                height+=getPaddingTop()+getPaddingBottom();
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
        }
        setMeasuredDimension(width,height);
    }


    //存放所有的view 是按照每一行的view来存储
    private List<List<View>> mAllViews=new ArrayList();
    //存储每一行的高度
    private List<Integer> mLineHeight=new ArrayList<Integer>();
    //布局
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mAllViews.clear();
        mLineHeight.clear();
        //得到当前ViewGroup的宽度
        int width=getWidth();
        int lineWidth=0;
        int lineHeight=0;
        List<View> lineViews=new ArrayList<>();
        for (int i=0;i<getChildCount();i++){
            View child = getChildAt(i);
            MarginLayoutParams lp= (MarginLayoutParams) child.getLayoutParams();
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();
            if(childWidth+lineWidth+lp.leftMargin+lp.rightMargin>width-getPaddingLeft()-getPaddingRight()){
                    mLineHeight.add(lineHeight);
                    mAllViews.add(lineViews);
                    //重置行宽
                    lineWidth=0;
                    lineHeight=childHeight+lp.topMargin+lp.bottomMargin;
                    lineViews=new ArrayList<>();
            }
            lineWidth+=childWidth+lp.leftMargin+lp.rightMargin;
            lineHeight=Math.max(lineHeight,childHeight+lp.topMargin+lp.bottomMargin);
            lineViews.add(child);
        }
        //处理最后一行
        mLineHeight.add(lineHeight);
        mAllViews.add(lineViews);

        //设置子view的位置
        int left=getPaddingLeft();
        int top=getPaddingTop();

        for (int i=0;i<mAllViews.size();i++){
            //得到当前行的高和视图
            lineViews = mAllViews.get(i);
            lineHeight=mLineHeight.get(i);


            for (int j=0;j<lineViews.size();j++){
                View child = lineViews.get(j);
                //判断可见性
                if(child.getVisibility()==View.GONE){
                    continue;
                }
                MarginLayoutParams lp= (MarginLayoutParams) child.getLayoutParams();
                int lc=left+lp.leftMargin;
                int tc=top+lp.topMargin;
                int rc=lc+child.getMeasuredWidth();
                int bc=tc+child.getMeasuredHeight();

                child.layout(lc,tc,rc,bc);
                left+=child.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;
            }
            left=getPaddingLeft();
            top+=lineHeight;
        }
    }


    /**
     * 这个方法主要是用于父容器添加子View时调用,
     用于生成和此容器类型相匹配的布局参数类。
     * @param attrs
     * @return
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(),attrs);
    }
}

猜你喜欢

转载自blog.csdn.net/owen_BLAND/article/details/80102514