先看下效果图

1、流式布局实现

继承ViewGroup,重写onMeasure,onLayout方法。代码如下:

package com.example.lin.flowlayoutdemo;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 lin.zhou on 2015/8/12. * 流式布局 */public class YhFlowLayout extends ViewGroup {    private List mLines = new ArrayList(); // 用来记录描述有多少行View    private Line mCurrrenLine;                                            // 用来记录当前已经添加到了哪一行    private int mHorizontalSpace = 10;    private int mVerticalSpace = 6;    public YhFlowLayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    public YhFlowLayout(Context context) {        super(context);    }    public void setSpace(int horizontalSpace, int verticalSpace) {        this.mHorizontalSpace = horizontalSpace;        this.mVerticalSpace = verticalSpace;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //清空        mLines.clear();        mCurrrenLine = null;        int layoutWidth = MeasureSpec.getSize(widthMeasureSpec);        // 获取行最大的宽度        int maxLineWidth = layoutWidth - getPaddingLeft() - getPaddingRight();        //测量孩子        int count = getChildCount();        for (int i = 0; i < count; i++) {            View v = getChildAt(i);            //如果孩子不可见            if (v.getVisibility() == GONE) {                continue;            }            measureChild(v, widthMeasureSpec, heightMeasureSpec);            // 往lines添加孩子            if (mCurrrenLine == null) {                // 说明还没有开始添加孩子                mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);                // 添加到 Lines中                mLines.add(mCurrrenLine);                // 行中一个孩子都没有                mCurrrenLine.addView(v);            } else {                // 行中有孩子了                Boolean canAdd = mCurrrenLine.canAdd(v);                if (canAdd) {                    mCurrrenLine.addView(v);                } else {                    //装不下,换行                    mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);                    mLines.add(mCurrrenLine);                    // 将view添加到line                    mCurrrenLine.addView(v);                }            }        }        // 设置自己的宽度和高度        int measuredWidth = layoutWidth;        float allHeight = 0;        for (int i = 0; i < mLines.size(); i++) {            float mHeigth = mLines.get(i).mHeigth;            // 加行高            allHeight += mHeigth;            // 加间距            if (i != 0) {                allHeight += mVerticalSpace;            }        }        int measuredHeight = (int) (allHeight + getPaddingTop() + getPaddingBottom() + 0.5f);        setMeasuredDimension(measuredWidth, measuredHeight);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // 给Child 布局---> 给Line布局        int paddingLeft = getPaddingLeft();        int offsetTop = getPaddingTop();        for (int i = 0; i < mLines.size(); i++) {            Line line = mLines.get(i);            // 给行布局            line.layout(paddingLeft, offsetTop);            offsetTop += line.mHeigth + mVerticalSpace;        }    }    class Line {        // 属性        private List mViews = new ArrayList();    // 用来记录每一行有几个View        private float mMaxWidth;                            // 行最大的宽度        private float mUsedWidth;                        // 已经使用了多少宽度        private float mHeigth;                            // 行的高度        private float mMarginLeft;        private float mMarginRight;        private float mMarginTop;        private float mMarginBottom;        private float mHorizontalSpace;                    // View和view之间的水平间距        // 构造        public Line(int maxWidth, int horizontalSpace) {            this.mMaxWidth = maxWidth;            this.mHorizontalSpace = horizontalSpace;        }        // 方法        /**         * 添加view,记录属性的变化         *         * @param view         */        public void addView(View view) {            // 加载View的方法            int size = mViews.size();            int viewWidth = view.getMeasuredWidth();            int viewHeight = view.getMeasuredHeight();            // 计算宽和高            if (size == 0) {                // 说还没有添加View                if (viewWidth > mMaxWidth) {                    mUsedWidth = mMaxWidth;                } else {                    mUsedWidth = viewWidth;                }                mHeigth = viewHeight;            } else {                // 多个view的情况                mUsedWidth += viewWidth + mHorizontalSpace;                mHeigth = mHeigth < viewHeight ? viewHeight : mHeigth;            }            // 将View记录到集合中            mViews.add(view);        }        /**         * 用来判断是否可以将View添加到line中         *         * @param view         * @return         */        public boolean canAdd(View view) {            // 判断是否能添加View            int size = mViews.size();            if (size == 0) {                return true;            }            int viewWidth = view.getMeasuredWidth();            // 预计使用的宽度            float planWidth = mUsedWidth + mHorizontalSpace + viewWidth;            if (planWidth > mMaxWidth) {                // 加不进去                return false;            }            return true;        }        /**         * 给孩子布局         *         * @param offsetLeft         * @param offsetTop         */        public void layout(int offsetLeft, int offsetTop) {            // 给孩子布局            int currentLeft = offsetLeft;            int size = mViews.size();            // 判断已经使用的宽度是否小于最大的宽度            float extra = 0;            float widthAvg = 0;            if (mMaxWidth > mUsedWidth) {                extra = mMaxWidth - mUsedWidth;                widthAvg = extra / size;            }            for (int i = 0; i < size; i++) {                View view = mViews.get(i);                int viewWidth = view.getMeasuredWidth();                int viewHeight = view.getMeasuredHeight();                // 判断是否有富余                if (widthAvg != 0) {                    // 改变宽度                    int newWidth = (int) (viewWidth + widthAvg + 0.5f);                    int widthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);                    int heightMeasureSpec = MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY);                    view.measure(widthMeasureSpec, heightMeasureSpec);                    viewWidth = view.getMeasuredWidth();                    viewHeight = view.getMeasuredHeight();                }                // 布局                int left = currentLeft;                int top = (int) (offsetTop + (mHeigth - viewHeight) / 2 +                        0.5f);                // int top = offsetTop;                int right = left + viewWidth;                int bottom = top + viewHeight;                view.layout(left, top, right, bottom);                currentLeft += viewWidth + mHorizontalSpace;            }        }    }}

2、Demo演示

布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin">    <com.example.lin.flowlayoutdemo.YhFlowLayout        android:id="@+id/flowlayout"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="10dp">    com.example.lin.flowlayoutdemo.YhFlowLayout>RelativeLayout>

下面根据需求设置一些流失布局中标签的属性:

 private void displayUI() {        for (int i = 0; i < mDatas.size(); i++) {            final String data = mDatas.get(i);            TextView tv = new TextView(this);            tv.setText(data);            tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);            tv.setGravity(Gravity.CENTER);            int paddingy = DisplayUtils.dp2Px(this, 7);            int paddingx = DisplayUtils.dp2Px(this, 6);            tv.setPadding(paddingx, paddingy, paddingx, paddingy);            tv.setClickable(false);            int shape = GradientDrawable.RECTANGLE;            int radius = DisplayUtils.dp2Px(this, 4);            int strokeWeight = DisplayUtils.dp2Px(this, 1);            int stokeColor = getResources().getColor(R.color.text_color_gray);            int stokeColor2 = getResources().getColor(R.color.green);            GradientDrawable normalBg = DrawableUtils.getShape(shape, radius, strokeWeight, stokeColor, Color.WHITE);            GradientDrawable pressedBg = DrawableUtils.getShape(shape, radius, strokeWeight, stokeColor2, getResources().getColor(R.color.green));            StateListDrawable selector = DrawableUtils.getSelector(normalBg, pressedBg);            tv.setBackgroundDrawable(selector);            ColorStateList colorStateList = DrawableUtils.getColorSelector(getResources().getColor(R.color.text_color_gray), getResources().getColor(R.color.white));            tv.setTextColor(colorStateList);            tv.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                }            });            flowLayout.addView(tv);        }    }

如果需要设置viewgroup的间距

   flowLayout = (YhFlowLayout)findViewById(R.id.flowlayout);        flowLayout.setSpace(DisplayUtils.dp2Px(this, 5), DisplayUtils.dp2Px(this, 5));        flowLayout.setPadding(DisplayUtils.dp2Px(this, 5), DisplayUtils.dp2Px(this, 5),                DisplayUtils.dp2Px(this, 5), DisplayUtils.dp2Px(this, 5));

ok,现在好看多了。

3、下面贴demo的下载地址

http://download.csdn.net/detail/zhoulin541/9574989

更多相关文章

  1. 解决ListView或ExpandableListView滚动时变黑
  2. Android(安卓)DataBinding 基础使用
  3. android 设置对话框的宽度和高度
  4. Android(安卓)PopWindow的简单应用
  5. 在页面添加一个透明Layout
  6. Android(安卓)ListView根据项数的大小自动改变高度
  7. 强大的 Android(安卓)属性动画 ObjectAnimator
  8. Android(安卓)EditView属性解析
  9. Android(安卓)Animation Tween动画效果的使用

随机推荐

  1. Android带表盘钟表控件AnalogClock
  2. Android模拟运行程序不显示
  3. Android的.9.png图片分析
  4. android音乐播放器-------使用android系
  5. android面试经典(6)
  6. Android(安卓)动态生成控件
  7. Android开发系列三:Android中怎么实现底部
  8. android实现可拖动按钮
  9. android-从音频数据库获取音乐数据
  10. android和ios,音频互通方案