浮动标签,面试总是被问到实现过程

package com.example.eventbus.floatview;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

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

/**
 * Created by MrWang on 2016/7/11.
 */
public class FlowLayout extends ViewGroup {
    //存储全部view 一个下标元素表明一行
    private List<List<View>> mAllView = new ArrayList<List<View>>();

    //记录高度
    private List<Integer> mLineHeight = new ArrayList<Integer>();

    //构造调用的时机
    //当new一个对象传入上下文调用此构造
    public FlowLayout(Context context) {
        this(context, null);
    }

    //在布局文件中写某个控件的一些属性时,但没有定义自定义属性的时候
    public FlowLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    //此构造用于写
    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    // MeasureSpec 包含测量模式(wrap_content fill_content math_content)、 测量值
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取FlowLayout布局模式或测量值
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        Log.d("onMeasure",(modeWidth == MeasureSpec.EXACTLY )+" flowWith:" + sizeWidth);

        //用于记录最终的行高
        int endWidth = 0;
        int endHeigth = 0;

        //用于循坏子view叠加当前的行高
        int lineWidth = 0;
        int lineHeight = 0;

        //获取子控件个数
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childAt = getChildAt(i); //Button

            //测量子View的值及相关LayoutParams
            //子View获得的LayoutParams的值是决定于位于它父类的Layoutparams的值
            measureChild(childAt, widthMeasureSpec, heightMeasureSpec);
            MarginLayoutParams lp = (MarginLayoutParams) childAt.getLayoutParams();

            //子view占居的宽度
            int childWidth = childAt.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            //子view占居的高度
            int childHeight = childAt.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

            //状况一 换行   (行宽 +子view宽度 大于FlowLayout布局最大宽度)
            if (lineWidth + childWidth > sizeWidth) {
                //记下最终的宽
                endWidth = Math.max(lineWidth, endWidth);
                //记录最终高度
                endHeigth += lineHeight;

                //重置叠加宽度
                lineWidth = childWidth;
                //重置叠加高度
                lineHeight = childHeight;
            } else {
                lineWidth += childWidth;
                lineHeight = Math.max(childHeight, lineHeight);
            }

            if (i == childCount - 1) {
                Log.d("onMeasure","最后一个元素"+ i);
                endWidth = Math.max(lineWidth, endWidth);
                endHeigth += lineHeight;//(childWidth
            }
        }

        Log.d("onMeasure", "sizeWidth: " + sizeWidth + " sizeHeight:" + sizeHeight);

        //判断模式 wrap_context、
        /*if (MeasureSpec.AT_MOST == modeHeight) {
            Log.d("FlowLayout","AT_MOST");
                      setMeasuredDimension(endWidth, endHeigth);
        } else {//math_context
            Log.d("FlowLayout","math_context");
            setMeasuredDimension(sizeWidth, sizeHeight);
        }*/

        setMeasuredDimension(
                modeWidth==MeasureSpec.EXACTLY?sizeWidth:endWidth,
                modeHeight==MeasureSpec.EXACTLY?sizeHeight:endHeigth

        );
       // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.d("onLayout","onLayout");
        //清空
        mAllView.clear();
        mLineHeight.clear();

        //获取ViewGroup宽度
        int width = getWidth();

        int lineWidth = 0;
        int lineHeight = 0;
        List<View> lineViews = new ArrayList<View>();
        int cCount = getChildCount();
        
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            //获取子View的Layoutparars
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

            //获取子View测量的宽高
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();
            //换行的条件
            if (lineWidth + childWidth + lp.leftMargin + lp.rightMargin > width) {
                //记录叠加后的行高
                mLineHeight.add(lineHeight);
                mAllView.add(lineViews);

                //重置行的 宽高
                lineWidth = 0;
                lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
                lineViews = new ArrayList<View>();
            }

            lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
            lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin);
            lineViews.add(child);
        }
        // for end  最后一行
        mLineHeight.add(lineHeight);
        mAllView.add(lineViews);

        //设置子View的位置
        int left = 0;
        int top = 0;
        //行数
        int lineNum = mAllView.size();
        for (int i = 0; i < lineNum; i++) {
            //每行 view及高
            lineViews = mAllView.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();
                //子View设置布局
                child.layout(lc, tc, rc, bc);
                left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            }

            left = 0;
            top += lineHeight;
        }
    }

    //生成layoutParamss
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }
}复制代码
相关文章
相关标签/搜索