自定义FlowLayout流式布局

 基于FlowLayout流式布局 扩展的接口,可设置每行最大的列数,以及文本是居左、居中还是居右布局。

修改后的代码如下:

package com.lanmeng.test.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;

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

/**
*
*/
public class FlowLayout extends ViewGroup {

    private static final String TAG = "FlowLayout";

    private List<Rect> mChildrenPositionList = new ArrayList<>();
    private int mMaxLines = Integer.MAX_VALUE;
    private int mMaxColumns = Integer.MAX_VALUE;
    private int mVisibleItemCount;

    public static final int LAYOUT_LEFT = 1;
    public static final int LAYOUT_CENTER = 2;
    public static final int LAYOUT_RIGHT = 3;
    private int mLayoutMode = LAYOUT_LEFT;

    /**
     * @param context
     */
    public FlowLayout(Context context) {
        super(context);
    }

    /**
     * @param context
     * @param attrs
     */
    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Construct
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mChildrenPositionList.clear();
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int[] a = helper(widthSize);
        int measuredHeight = 0;
        if (heightMode == MeasureSpec.EXACTLY) {
            measuredHeight = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            measuredHeight = a[0];
        }
        int measuredWidth = 0;
        if (widthMode == MeasureSpec.EXACTLY) {
            measuredWidth = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            measuredWidth = a[1];
        }

        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    private int[] helper(int widthSize) {
        boolean isOneRow = true;
        int width = getPaddingLeft();
        int height = getPaddingTop();
        int rightPadding = getPaddingRight();
        int maxHeight = 0;
        int currLine = 1;
        List<Integer> positions = new LinkedList<Integer>();
        int count = 0; //line count;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            LayoutParams params = child.getLayoutParams();
            MarginLayoutParams mlp;
            if (params instanceof MarginLayoutParams) {
                mlp = (MarginLayoutParams) params;
            } else {
                mlp = new MarginLayoutParams(params);
            }
            int childWidth = mlp.leftMargin + child.getMeasuredWidth() + mlp.rightMargin;
            int childHeight = mlp.topMargin + child.getMeasuredHeight() + mlp.bottomMargin;
            maxHeight = Math.max(maxHeight, childHeight);
            // Change line or not
            if (width + childWidth + getPaddingRight() > widthSize || count >= mMaxColumns) {
                height += maxHeight;
                width = getPaddingLeft();
                maxHeight = childHeight;
                isOneRow = false;
                currLine++;
                count = 0;
                if (i > 1) {
                    positions.add(i - 1);
                }
                if (currLine > mMaxLines) {
                    break;
                }
            }
            count++;
            Rect rect = new Rect(width + mlp.leftMargin,
                    height + mlp.topMargin,
                    width + childWidth - mlp.rightMargin,
                    height + childHeight - mlp.bottomMargin);
            mChildrenPositionList.add(rect);
            width += childWidth;
        }
        if (getChildCount() > 0) {
            positions.add(getChildCount() - 1);
        }

        //recalculate position by layout mode
        int uselessSpace = 0;
        int startLayoutPosition = 0;
        int startIndex = 0;
        int endIndex = 0;
        for (int i = 0; i < positions.size(); i++) {
            if (i == 0) {
                startIndex = 0;
            } else {
                startIndex = positions.get(i - 1) + 1;
            }
            endIndex = positions.get(i);
//            Log.d(TAG, "startIndex: " + startIndex + ", endIndex: " + endIndex);
            uselessSpace = widthSize - mChildrenPositionList.get(endIndex).right - rightPadding;
            switch (mLayoutMode) {
                case LAYOUT_LEFT:
                    startLayoutPosition = 0;
                    break;
                case LAYOUT_CENTER:
                    startLayoutPosition = uselessSpace / 2;
                    break;
                case LAYOUT_RIGHT:
                    startLayoutPosition = uselessSpace;
                    break;
                default:
                    break;
            }
            for (int j = startIndex; j <= endIndex; j++) {
                Rect rect = mChildrenPositionList.get(j);
//                Log.d(TAG, "i: " + j + " ---left.left: " + rect.left + " ---left.right: " + rect.right);
                rect.left += startLayoutPosition;
                rect.right += startLayoutPosition;
            }
        }

        int[] res = new int[2];
        res[0] = height + maxHeight + getPaddingBottom();
        res[1] = isOneRow ? width + getPaddingRight() : widthSize;

        return res;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int n = Math.min(getChildCount(), mChildrenPositionList.size());
        for (int i = 0; i < n; i++) {
            View child = getChildAt(i);
            Rect rect = mChildrenPositionList.get(i);
            child.layout(rect.left, rect.top, rect.right, rect.bottom);
        }
        mVisibleItemCount = n;
    }

    /**
     * set Adapter
     */
    public void setAdapter(Adapter adapter) {
        removeAllViews();
        int n = adapter.getItemCount();
        for (int i = 0; i < n; i++) {
            ViewHolder holder = adapter.onCreateViewHolder(this);
            adapter.onBindViewHolder(holder, i);
            View child = holder.itemView;
            addView(child);
        }
    }

    /**
     * set max lines
     */
    public void setMaxLines(int maxLines) {
        mMaxLines = maxLines;
    }

    /**
     * set max Columns
     */
    public void setMaxColumns(int columns) {
        mMaxColumns = columns;
    }

    /**
     * layout left, center or right.
     * @param mLayoutMode 
     */
    public void setLayoutMode(int mLayoutMode) {
        this.mLayoutMode = mLayoutMode;
    }

    /**
     * getVisibleItemCount
     *
     * @return
     */
    public int getVisibleItemCount() {
        return mVisibleItemCount;
    }

    /**
     * @param <VH>
     */
    public abstract static class Adapter<VH extends ViewHolder> {

        /**
         * @param parent
         * @return
         */
        public abstract VH onCreateViewHolder(ViewGroup parent);

        /**
         * @param holder
         * @param position
         */
        public abstract void onBindViewHolder(VH holder, int position);

        /**
         * @return
         */
        public abstract int getItemCount();

    }

    public abstract static class ViewHolder {
        public final View itemView;

        /**
         * @param itemView
         */
        public ViewHolder(View itemView) {
            if (itemView == null) {
                throw new IllegalArgumentException("itemView may not be null");
            }
            this.itemView = itemView;
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值