浮動標籤,面試總是被問到實現過程

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);
    }
}複製代碼
相關文章
相關標籤/搜索