1. 程式人生 > >Android 自定義流式佈局(快速實現)

Android 自定義流式佈局(快速實現)

首先先寫一個自定義的類繼承viewgroup,程式碼如下

package com.demo.com.jd_zhang.ui.customview;

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

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

/**
 * Created by Administrator on 2018/9/25.
 */

public class FlowGroupView extends ViewGroup {
    /**
     * 儲存所有的view 按行記錄
     */
    private List<List<View>> mAllViews = new ArrayList<List<View>>();
    /**
     * 記錄每一行的高度
     */
    private List<Integer> mLineHeight = new ArrayList<Integer>();
    private String TAG = "TAG";

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

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

    public FlowGroupView(Context context) {
        super(context);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mAllViews.clear();
        mLineHeight.clear();
        //得到上級容器為其推薦的寬高和計算模式
        int specWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int specHeighMode = MeasureSpec.getMode(heightMeasureSpec);
        int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        int specHeighSize = MeasureSpec.getSize(heightMeasureSpec);
        int width = 0;
        int height = 0;
        // 得到子view的個數
        int cCount = getChildCount();
        /**
         * 記錄每一行的寬度,width不斷取最大寬度
         */
        int lineWidth = 0;
        /**
         * 每一行的高度,累加至height
         */
        int lineHeight = 0;

        // 儲存每一行所有的childView
        List<View> lineViews = new ArrayList<View>();

        for (int i = 0; i < cCount; i++) {
            // 得到每個子View
            View child = getChildAt(i);
            // 測量每個子View的寬高
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            // 當前子view的lp
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            // 子view的寬和高
            int cWidth = 0;
            int cheight = 0;

            cWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;

            cheight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            lineHeight = cheight;

            if (lineWidth + cWidth > specWidthSize) {
                width = Math.max(lineWidth, cWidth);
                lineWidth = cWidth;

                mAllViews.add(lineViews);
                mLineHeight.add(cheight);
                lineViews = new ArrayList<>();

                lineViews.add(child);
                height += cheight;
                Log.e("需要換行", "hight--" + height);
                Log.e("onMeasure", "AllViews.size()  --  > " + mAllViews.size());
            } else {

                lineWidth += cWidth;
                Log.e("不需要換行", "hight--" + height);

                lineViews.add(child);
            }

            if (i == cCount - 1) {
                // 如果是最後一個view
                width = Math.max(lineWidth, cWidth);
                height += cheight;
                Log.e("最後一個view", "hight--" + height);
            }
        }

        mLineHeight.add(lineHeight);
        mAllViews.add(lineViews);

        setMeasuredDimension(
                specWidthMode == MeasureSpec.EXACTLY ? specWidthSize : width,
                specHeighMode == MeasureSpec.EXACTLY ? specHeighSize : height
        );
        Log.e("onMeasure", "mAllViews.size() -- > " + mAllViews.size() + "   mLineHeight.size() -- > " + mLineHeight.size() + "Height -- > " + height);
    }

    /**
     * 所有childView的位置的佈局
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        int lineHeight = 0;

        List<View> lineViews = new ArrayList<View>();
        int left = 0;
        int top = 0;

        int lineNums = mAllViews.size();
        for (int i = 0; i < lineNums; i++) {

            lineViews = mAllViews.get(i);

            lineHeight = mLineHeight.get(i);

            Log.e("onLayout", "第" + i + "行 :" + lineViews.size() + "-------lineHeight" + lineHeight);

            // 遍歷當前行所有的View
            for (int j = 0; j < lineViews.size(); j++) {
                View child = lineViews.get(j);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

                //計算childView的left,top,right,bottom
                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.rightMargin + lp.leftMargin;
            }
            left = 0;
            top += lineHeight;
        }
        Log.v("onLayout", "onLayout   mAllViews.size() -- > " + mAllViews.size() + "   mLineHeight.size() -- > " + mLineHeight.size());
    }


    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {

        return new MarginLayoutParams(getContext(), attrs);
    }

}

然後在activity裡引用

 private ArrayList<String> names;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        ButterKnife.bind(this);
        setTwoFlowLayout();

    }

    private void setTwoFlowLayout() {
        //新增資料
        names = new ArrayList<String>();
        names.add("筆記本");
        names.add("空氣進化器");
        names.add("空調");
        names.add("電腦");
        names.add("華為");
        names.add("小米");
        names.add("機械誡命");
        names.add("vivo");
        //為佈局新增內容
        for (int i = 0; i < names.size(); i++) {
            addTextView(names.get(i));
        }

    }

    /**
     * 動態添加布局
     *
     * @param str
     */
    private void addTextView(String str) {
        TextView child = new TextView(this);
        ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.WRAP_CONTENT, ViewGroup.MarginLayoutParams.WRAP_CONTENT);
        params.setMargins(5, 5, 5, 5);
        child.setLayoutParams(params);
        child.setBackgroundResource(R.drawable.flag);
        child.setText(str);
        child.setTextColor(Color.WHITE);
        initEvents(child);//監聽
        myFlowLayout.addView(child);
    }

    //    /**
    //     * 為每個view 新增點選事件
    //     */
    private void initEvents(final TextView tv) {
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(SearchActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
                Intent intent2 = new Intent(SearchActivity.this, ProductDetailsActivity.class);
                intent2.putExtra("name", tv.getText().toString());
                startActivity(intent2);
            }
        });
    }