Android简单自定义流式布局

   网上很多类似adapter形式的添加标签的流式布局,由于新的需求,没有必要那么麻烦,所以就自己定义了简单展示的流式布局的样式。
   内部元素可以根据自己的条件来隐藏展示gone或visible,达到动态展示多少的效果。仅作参考。复杂的还是使用adapter形式的流式布局展示。

先上代码:

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

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

import cn.gome.staff.buss.guide.R;

public class FlexboxLayout extends LinearLayout {

    public FlexboxLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        resolveAttrs(context, attrs);
    }

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

    public FlexboxLayout(Context context) {
        super(context);
        resolveAttrs(context, null);
    }


    private void resolveAttrs(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlexboxLayout);
        int lineAlignment = a.getInt(R.styleable.FlexboxLayout_lineAlignment, 0);
        switch (lineAlignment) {
            case 0:
                mLineAlignment = FlexAlign.TopTop;
                break;
            case 1:
                mLineAlignment = FlexAlign.TopCenter;
                break;
            case 2:
                mLineAlignment = FlexAlign.TopBottom;
                break;
            case 3:
                mLineAlignment = FlexAlign.CenterTop;
                break;
            case 4:
                mLineAlignment = FlexAlign.CenterCenter;
                break;
            case 5:
                mLineAlignment = FlexAlign.CenterBottom;
                break;
            case 6:
                mLineAlignment = FlexAlign.BottomTop;
                break;
            case 7:
                mLineAlignment = FlexAlign.BottomCenter;
                break;
            case 8:
                mLineAlignment = FlexAlign.BottomBottom;
                break;
        }
        mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlexboxLayout_horizontalSpacing, 0);
        mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlexboxLayout_verticalSpacing, 0);
        a.recycle();
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    private FlexAlign mLineAlignment;
    private int mHorizontalSpacing;
    private int mVerticalSpacing;

    public FlexAlign getLineAlignment() {
        return mLineAlignment;
    }

    public void setLineAlignment(FlexAlign alignment) {
        mLineAlignment = alignment;
    }

    public int getHorizontalSpacing() {
        return mHorizontalSpacing;
    }

    public void setHorizontalSpacing(int spacing) {
        if (spacing >= 0)
            mHorizontalSpacing = spacing;
    }

    public int getVerticalSpacing() {
        return mVerticalSpacing;
    }

    public void setVerticalSpacing(int spacing) {
        if (spacing >= 0)
            mVerticalSpacing = spacing;
    }

    private int computeWidth(List widths) {
        int maxWidth = 0;
        for (Integer width : widths) {
            maxWidth = Math.max(maxWidth, width);
        }
        return maxWidth + getPaddingLeft() + getPaddingRight();
    }

    private int computeHeight(List heights) {
        int heightSum = 0;
        for (Integer height : heights) {
            heightSum += height;
        }
        int lineCount = heights.size();
        if (lineCount > 1) {
            heightSum += (lineCount - 1) * mVerticalSpacing;
        }
        return heightSum + getPaddingTop() + getPaddingBottom();
    }

    private List getVisibleChildViews() {
        List visibleChildViews = new ArrayList<>();
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            int childViewVisibility = childView.getVisibility();
            if (childViewVisibility != View.GONE) {
                visibleChildViews.add(childView);
            }
        }
        return visibleChildViews;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();

        List widths = new ArrayList<>();
        List heights = new ArrayList<>();

        int lineWidth = 0;
        int lineHeight = 0;

        List visibleChildViews = getVisibleChildViews();
        int visibleChildViewCount = visibleChildViews.size();
        for (int i = 0; i < visibleChildViewCount; i++) {
            View visibleChildView = visibleChildViews.get(i);
            measureChild(visibleChildView, widthMeasureSpec, heightMeasureSpec);
            MarginLayoutParams mlp = (MarginLayoutParams) visibleChildView.getLayoutParams();

            int childWidth = visibleChildView.getMeasuredWidth() + mlp.leftMargin + mlp.rightMargin;
            int childHeight = visibleChildView.getMeasuredHeight() + mlp.topMargin + mlp.bottomMargin;

            if (i == 0) {
                lineWidth = childWidth;
                lineHeight = childHeight;
            } else {
                if (lineWidth + mHorizontalSpacing + childWidth <= widthSize - paddingLeft - paddingRight) {
                    lineWidth += mHorizontalSpacing + childWidth;
                    lineHeight = Math.max(lineHeight, childHeight);
                } else {
                    widths.add(lineWidth);
                    heights.add(lineHeight);
                    lineWidth = childWidth;
                    lineHeight = childHeight;
                }
            }
            if (i == visibleChildViewCount - 1) {
                widths.add(lineWidth);
                heights.add(lineHeight);
            }
        }

        int computedWidth = computeWidth(widths);
        int computedHeight = computeHeight(heights);

        int measuredWidth = 0;
        int measuredHeight = 0;

        int minWidth = getSuggestedMinimumWidth();
        int minHeight = getSuggestedMinimumHeight();

        switch (widthMode) {
            case MeasureSpec.EXACTLY:
                measuredWidth = widthSize;
                break;
            case MeasureSpec.AT_MOST:
                measuredWidth = Math.max(computedWidth, minWidth);
                measuredWidth = Math.min(widthSize, measuredWidth);
                break;
            case MeasureSpec.UNSPECIFIED:
                measuredWidth = Math.max(computedWidth, minWidth);
                break;
        }

        switch (heightMode) {
            case MeasureSpec.EXACTLY:
                measuredHeight = heightSize;
                break;
            case MeasureSpec.AT_MOST:
                measuredHeight = Math.max(computedHeight, minHeight);
                measuredHeight = Math.min(heightSize, measuredHeight);
                break;
            case MeasureSpec.UNSPECIFIED:
                measuredHeight = Math.max(computedHeight, minHeight);
                break;
        }

        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    private void layoutLineViews(List lineViews, int lineLeft, int lineTop, int lineWidth, int lineHeight) {
        for (View view : lineViews) {
            MarginLayoutParams viewMLP = (MarginLayoutParams) view.getLayoutParams();
            int viewW = view.getMeasuredWidth() + viewMLP.leftMargin + viewMLP.rightMargin;
            int viewH = view.getMeasuredHeight() + viewMLP.topMargin + viewMLP.bottomMargin;
            int viewL = lineLeft + viewMLP.leftMargin;
            int viewT = mLineAlignment.getY(lineTop, lineHeight, viewH) + viewMLP.topMargin;
            int viewR = viewL + view.getMeasuredWidth();
            int viewB = viewT + view.getMeasuredHeight();

            view.layout(viewL, viewT, viewR, viewB);

            lineLeft += viewW + mHorizontalSpacing;
        }
        lineViews.clear();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int w = r - l;
        int h = b - t;

        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();

        int lineLeft = 0;
        int lineTop = 0;
        int lineWidth = 0;
        int lineHeight = 0;

        List lineViews = new ArrayList<>();

        List visibleChildViews = getVisibleChildViews();
        int visibleChildViewCount = visibleChildViews.size();

        for (int i = 0; i < visibleChildViewCount; i++) {
            View visibleChildView = visibleChildViews.get(i);
            MarginLayoutParams mlp = (MarginLayoutParams) visibleChildView.getLayoutParams();

            int childWidth = visibleChildView.getMeasuredWidth() + mlp.leftMargin + mlp.rightMargin;
            int childHeight = visibleChildView.getMeasuredHeight() + mlp.topMargin + mlp.bottomMargin;

            if (i == 0) {
                lineLeft = paddingLeft;
                lineTop = paddingTop;
                lineWidth = childWidth;
                lineHeight = childHeight;
                lineViews.add(visibleChildView);
            } else {
                if (lineWidth + mHorizontalSpacing + childWidth <= w - paddingLeft - paddingRight) {
                    lineWidth += mHorizontalSpacing + childWidth;
                    lineHeight = Math.max(lineHeight, childHeight);
                    lineViews.add(visibleChildView);
                } else {
                    layoutLineViews(lineViews, lineLeft, lineTop, lineWidth, lineHeight);

                    lineLeft = paddingLeft;
                    lineTop += lineHeight + mVerticalSpacing;
                    lineWidth = childWidth;
                    lineHeight = childHeight;
                    lineViews.add(visibleChildView);
                }
            }
            if (i == visibleChildViewCount - 1) {
                layoutLineViews(lineViews, lineLeft, lineTop, lineWidth, lineHeight);
            }
        }

    }

    private boolean mSuperHandledTouchEvent;

    private boolean onSuperTouchEvent(MotionEvent event) {
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            mSuperHandledTouchEvent = super.onTouchEvent(event);
        } else {
            if (mSuperHandledTouchEvent) {
                mSuperHandledTouchEvent = super.onTouchEvent(event);
            }
        }
        return mSuperHandledTouchEvent;
    }

}

引用的一个类:


public enum FlexAlign {

    TopTop,
    TopCenter,
    TopBottom,
    CenterTop,
    CenterCenter,
    CenterBottom,
    BottomTop,
    BottomCenter,
    BottomBottom;

    public int getY(int baseY, int baseHeight, int height) {
        switch (this) {
            case TopTop:
                return baseY;
            case TopCenter:
                return baseY - height / 2;
            case TopBottom:
                return baseY - height;
            case CenterTop:
                return baseY + baseHeight / 2;
            case CenterCenter:
                return baseY + (baseHeight - height) / 2;
            case CenterBottom:
                return baseY + baseHeight / 2 - height;
            case BottomTop:
                return baseY + baseHeight;
            case BottomCenter:
                return baseY + baseHeight - height / 2;
            case BottomBottom:
                return baseY + baseHeight - height;
            default:
                return baseY + (baseHeight - height) / 2;
        }
    }

    public float getY(float baseY, float baseHeight, float height) {
        switch (this) {
            case TopTop:
                return baseY;
            case TopCenter:
                return baseY - height / 2;
            case TopBottom:
                return baseY - height;
            case CenterTop:
                return baseY + baseHeight / 2;
            case CenterCenter:
                return baseY + (baseHeight - height) / 2;
            case CenterBottom:
                return baseY + baseHeight / 2 - height;
            case BottomTop:
                return baseY + baseHeight;
            case BottomCenter:
                return baseY + baseHeight - height / 2;
            case BottomBottom:
                return baseY + baseHeight - height;
            default:
                return baseY + (baseHeight - height) / 2;
        }
    }

}

values里面的attrs.xml属性


        
            
            
            
            
            
            
            
            
            
        
        
        
    

引入方法很简单,直接在xml里面引入




    

    

        

你可能感兴趣的:(Android简单自定义流式布局)