流式布局控件的编写

这里写图片描述


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

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

/**
 * 作者: willkong on 2017/11/15.
 * 作用:流式布局
 */
public class FlowLayout extends ViewGroup{
    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);
    }

    //能够设置当前布局的宽度和高度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取设置的宽高的模式和具体的值
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        //如果用户使用的至多模式,那么使用如下的两个变量计算真实的宽高值
        int width = 0;
        int height= 0;
        //每一行的宽度和高度
        int lineWidth = 0;
        int lineHeight = 0;
        //获取子视图
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);

            //只有调用了如下的方法,方可计算子视图的测量的宽高
            measureChild(childView,widthMeasureSpec,heightMeasureSpec);

            //获取子视图的宽高
            int childWidth = childView.getMeasuredWidth();
            int childHeight = childView.getMeasuredHeight();
            //要想保证可以获取子视图的边距参数对象,必须重写generateLayoutParams()
            MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams();

            if (lineWidth + childWidth + mp.leftMargin+mp.rightMargin<widthSize){//不换行
                lineWidth += childWidth + mp.leftMargin+mp.rightMargin;
                lineHeight = Math.max(lineHeight,childHeight+mp.topMargin+mp.bottomMargin);
            }else {//换行
                width = Math.max(width,lineWidth);
                height+=lineHeight;
                //重置更新一行的宽高
                lineWidth = childWidth + mp.leftMargin+mp.rightMargin;
                lineHeight = childHeight+mp.topMargin+mp.bottomMargin;
            }
            //最后一个元素--如果最后一个不换行,宽高没有计算,不准确,所以需要下面的代码执行计算
            //不管有没有换行,最后一行都要加上,不然,最后一行就没有显示了。
            if (i==childCount-1){
                width = Math.max(width,lineWidth);
                height+=lineHeight;
            }
        }

        //设置当前流式布局的宽高
        setMeasuredDimension(widthMode==MeasureSpec.EXACTLY?widthSize:width,heightMode==MeasureSpec.EXACTLY?heightSize:height);
    }

    //布局:给每一个子视图指定显示的位置,childView.layout()
    private List<List<View>>allViews = new ArrayList<>();//每一行的子视图的集合构成的集合
    private List<Integer>allHeights = new ArrayList<>();//每一行的高度构成的集合。
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //一、给两个集合添加元素

        //每一行的宽度和高度
        int lineWidth = 0;
        int lineHeight = 0;

        //提供一个集合,保存一行childView
        List<View>lineList = new ArrayList<>();
        //获取布局的宽度
        int width = this.getMeasuredWidth();

        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            //获取视图的测量宽高、边距
            int childWidth = childView.getMeasuredWidth();
            int childHeight = childView.getMeasuredHeight();
            MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams();

            if (lineWidth+childView.getMeasuredWidth()+mp.leftMargin+mp.rightMargin<=width){//不换行
                lineList.add(childView);
                lineWidth+=childWidth+mp.leftMargin+mp.rightMargin;
                lineHeight = Math.max(lineHeight,childHeight+mp.topMargin+mp.bottomMargin);
            }else {//换行
                allViews.add(lineList);
                allHeights.add(lineHeight);

                lineWidth = childWidth+mp.leftMargin+mp.rightMargin;
                lineHeight = childHeight+mp.topMargin+mp.bottomMargin;
                lineList = new ArrayList<>();
                lineList.add(childView);
            }

            if (i == childCount-1){//如果是最后一个元素
                allViews.add(lineList);
                allHeights.add(lineHeight);
            }

        }
        //二、给每一个子视图指定显示的位置
        int x=0;
        int y=0;
        for (int i = 0; i < allViews.size(); i++) {//每遍历一次,对应一行元素
            List<View>lineViews = allViews.get(i);//取出当前行构成的集合
            for (int j = 0; j < lineViews.size(); j++) {
                View childView = lineViews.get(j);
                int childWidth = childView.getMeasuredWidth();
                int childHeight = childView.getMeasuredHeight();
                MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams();
                int left = x + mp.leftMargin;
                int top = y + mp.topMargin;
                int right = left + childView.getMeasuredWidth();
                int bottom = top + childView.getMeasuredHeight();

                childView.layout(left,top,right,bottom);

                x+= childWidth + mp.leftMargin + mp.rightMargin;
            }
            y += allHeights.get(i);
            x = 0;
        }
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        MarginLayoutParams mp = new MarginLayoutParams(getContext(), attrs);
        return mp;
    }
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.willkong.p2pclient.fragment.ProductListFragment">

    <com.willkong.p2pclient.ui.FlowLayout
        android:id="@+id/flow_hot"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_blue_light">
        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="你是我心内的一首歌"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="涛声依旧"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="夜夜"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="月落乌啼霜满天"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="哇塞"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="word天哪"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="你咋不上天呢"
        android:layout_margin="10dp"
        android:textSize="20sp" />


        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="你想怎样"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="夜曲"
        android:layout_margin="10dp"
        android:textSize="20sp" />
    </com.willkong.p2pclient.ui.FlowLayout>
</LinearLayout>

需要注意的是,要想保证可以获取子视图的边距参数对象,必须重写generateLayoutParams()方法。

动态加载数据:


import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.loopj.android.http.RequestParams;
import com.willkong.p2pclient.R;
import com.willkong.p2pclient.common.BaseFragment;
import com.willkong.p2pclient.ui.FlowLayout;
import com.willkong.p2pclient.util.DrawUtils;
import com.willkong.p2pclient.util.UIUtils;

import java.util.Random;

import butterknife.Bind;

public class ProductHotFragment extends BaseFragment {
    @Bind(R.id.flow_hot)
    FlowLayout flowHot;
    private String[] datas = new String[]{"新手福利计划", "财神道90天计划", "硅谷计划", "30天理财计划", "180天理财计划", "月月升", "中情局投资商业经营", "大学老师购买车辆", "屌丝下海经商计划", "美人鱼影视拍摄投资", "Android培训老师自己周转", "养猪场扩大经营",
            "旅游公司扩大规模", "摩托罗拉洗钱计划", "铁路局回款计划", "屌丝迎娶白富美计划"
    };

    @Override
    protected RequestParams getParams() {
        return null;
    }

    @Override
    protected String getUrl() {
        return null;
    }

    @Override
    protected void initData(String content) {
        for (int i = 0; i < datas.length; i++) {
            final TextView tv = new TextView(getContext());
            tv.setText(datas[i]);
            ViewGroup.MarginLayoutParams mp = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            mp.leftMargin = UIUtils.dp2px(10);
            mp.topMargin = UIUtils.dp2px(10);
            mp.rightMargin = UIUtils.dp2px(10);
            mp.bottomMargin = UIUtils.dp2px(10);
            tv.setLayoutParams(mp);//设置边距
            int padding = UIUtils.dp2px(5);
            tv.setPadding(padding,padding,padding,padding);//设置内边距
            tv.setTextSize(UIUtils.dp2px(5));

            Random random = new Random();
            int red = random.nextInt(211);
            int green = random.nextInt(211);
            int blue = random.nextInt(211);
            //设置背景
//            tv.setBackground(DrawUtils.getDrawable(Color.rgb(red,green,blue),UIUtils.dp2px(5)));
            //设置具有选择器的背景
            tv.setBackground(DrawUtils.getSelector(DrawUtils.getDrawable(Color.rgb(red,green,blue),UIUtils.dp2px(5)),DrawUtils.getDrawable(Color.WHITE,UIUtils.dp2px(5))));
            //设置textView是可点击的
//            tv.setClickable(true);
            tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    UIUtils.toast(tv.getText().toString().trim(),false);
                }
            });

            flowHot.addView(tv);
        }
    }

    @Override
    protected void initTitle() {

    }

    @Override
    public int getLayoutId() {
        return R.layout.fragment_product_hot;
    }
}

DrawUtils.class


import android.annotation.SuppressLint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
public class DrawUtils {
    @SuppressLint("WrongConstant")
    public static Drawable getDrawable(int rgb, int radius){
        GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setColor(rgb);
        gradientDrawable.setGradientType(GradientDrawable.RECTANGLE);//矩形
        gradientDrawable.setCornerRadius(radius);//四周圆角半径
        gradientDrawable.setStroke(UIUtils.dp2px(1),rgb);//边框厚度与颜色
        return gradientDrawable;
    }

    public static StateListDrawable getSelector(Drawable normalDrawable,Drawable pressDrawable){
        StateListDrawable stateListDrawable = new StateListDrawable();
        //给当前的颜色选择器添加选中图片选中指向状态,未选中图片指向状态
        stateListDrawable.addState(new int[]{android.R.attr.state_enabled,android.R.attr.state_pressed},pressDrawable);
        stateListDrawable.addState(new int[]{android.R.attr.state_enabled},normalDrawable);
        //设置默认状态
        stateListDrawable.addState(new int[]{},normalDrawable);
        return stateListDrawable;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值