自定义流式布局(应用:热门标签,照片)

流式布局(应用:热门标签,照片)


自定义ViewGroup
1.onMeasure:测量子View的宽和高,设置自己的宽和高
onMeasure根据子View的布局文件,为子View设置测量模式和测量值。

测量:包括测量模式和测量值

测量模式包裹以下三种模式:
1.EXACTLY:是指显示指定大小时,例如:100dp,match_parent
2.AT_MOST:wrap_content
3.UNSPCIFIED:子View想要多大就给他多大,一般出现在ScroolView中,很少见


2.onLayout:设置子View的位置


ViewGroup会对应一个LayoutParams
子View.getLayoutParams()获得的是父控件的LayoutParameters

    这里我们只需要知道子空间之间的间距,所以我们只需要指定我们LayoutParams为MarginLayoutParameters即可,

当然在实际开发中我们应该根据需要来选择LayoutParams,也可以自定义LayoutParams。

效果:



代码如下:

package com.example.liaoli.customflowlayout.view;

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

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

/**
 * Created by liaoli on 2015/11/16.
 */
public class FlawLayout extends ViewGroup {
    public FlawLayout(Context context) {
        super(context);
    }

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

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



    /**
     * 測量子類的寬和高,以便確定自己的寬和高
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int mWidth = MeasureSpec.getSize(widthMeasureSpec);
        int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);

        int mHeight = MeasureSpec.getSize(heightMeasureSpec);
        int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);


        int childCount = getChildCount();

        //記錄wrap_content時候FlawLayout的寬和高
        int wrapContentWidth = 0;
        int wrapContentHeight= 0;


        //記錄每一行的寬度和高度
        int lineWidth = 0;
        int lineHeight = 0;
        for(int i = 0;i < childCount;i++){
            View child = getChildAt(i);

            //測量每一個子View的寬和高
            measureChild(child, widthMeasureSpec, heightMeasureSpec);

           MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();

            //得到計算子View佔據的寬度和高度

            int childWidthInParent = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
            int childHeightInParent = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;




            if (lineWidth + childWidthInParent > mWidth - getPaddingLeft() - getPaddingRight()) {

                //此時要換行,行的高度增加
                wrapContentHeight += lineHeight;

                //此時一行的寬度已經可以確定,如果行寬比原來的最大行寬大,則寬度變為大的
                wrapContentWidth = Math.max(lineWidth,wrapContentWidth);

                //換行后充值行寬和行高
                lineHeight = childHeightInParent;
                lineWidth = childWidthInParent;

            }else {

               //不換行,本行寬度增加
                lineWidth += childWidthInParent;
                //不換行,本行高度有可能變化
                lineHeight = Math.max(lineHeight,childHeightInParent);
            }

            if(i == childCount -1){
                //如果是最後一個Child,要將此次View所在的行高加上
                wrapContentHeight += lineHeight;
                //比較最後一行與之前的最大寬度進行比較,去打的作為wrap_content的寬度
                wrapContentWidth = Math.max(lineWidth,wrapContentWidth);
            }

        }

        setMeasuredDimension(widthMeasureMode == MeasureSpec.EXACTLY ? mWidth:wrapContentWidth+getPaddingLeft()+getPaddingRight(),
                heightMeasureMode == MeasureSpec.EXACTLY ? mHeight:wrapContentHeight+getPaddingTop() + getPaddingBottom());


    }


    List<List<View>> allchildViews =  new ArrayList<>();
    List<Integer> lineHeights = new ArrayList<>();

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {


        allchildViews.clear();
        lineHeights.clear();

        int mwidth = getWidth();

        //記錄每一行的寬度和高度
        int lineWidth = 0;
        int lineHeight = 0;

        List<View> lineViews = new ArrayList<>();
        int childCount = getChildCount();

        for(int i = 0 ; i < childCount ; i++){

            View child = getChildAt(i);

            MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();

            int childWidth = child.getMeasuredWidth()+ layoutParams.leftMargin + layoutParams.rightMargin;;

            int childHeight = child.getMeasuredHeight()+ layoutParams.topMargin + layoutParams.bottomMargin;;

            if(lineWidth + childWidth > mwidth -getPaddingLeft() - getPaddingRight()){

                //换行
                lineHeights.add(lineHeight);

                lineWidth = 0;
                lineHeight = childHeight;
                allchildViews.add(lineViews);

                lineViews = new ArrayList<>();

            }

                //不换行
                lineWidth += childWidth;
                lineHeight = Math.max(childHeight,lineHeight);
                lineViews.add(child);



            if(i == childCount -1){
                //要將此次View所在的行高加上最后一行的行高
                lineHeights.add(lineHeight);
                //左后一行的view
                allchildViews.add(lineViews);
            }

        }

        int left = getPaddingLeft();
        int top = getPaddingTop();

        int lineNumbers = lineHeights.size();

        for(int i = 0 ; i < lineNumbers ; i++){

            lineViews = allchildViews.get(i);
            lineHeight = lineHeights.get(i);

            for(int j = 0 ; j < lineViews.size() ; j++){
                View child = lineViews.get(j);

                if(child.getVisibility() == View.GONE){
                    continue;
                }

                MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();

                int childTopInparent = top + layoutParams.topMargin;

                int childBottomInparent = top + layoutParams.topMargin +child.getMeasuredHeight();

                int childLeftInparent = left + layoutParams.leftMargin;

                int childRightInparent = left + layoutParams.leftMargin + child.getMeasuredWidth() ;

                child.layout(childLeftInparent,childTopInparent,childRightInparent,childBottomInparent);

                //下一个Viewleft其实点
                left += layoutParams.leftMargin + child.getMeasuredWidth()+ layoutParams.rightMargin;
            }

            //每一行完毕后,left又回到最左边,二top则增加了一行
            left = getPaddingLeft();
            top += lineHeight;
        }
    }

    /**
     * 指定我們自己想要的LayoutParams,如果現有的LayoutParams不能滿足需求,我們科以自定義
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(),attrs);
    }
}

源码:http://pan.baidu.com/s/1jG1yrvo


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值