android搜索热词(热门标签)流式布局的实现

来源:互联网 发布:python beaker 编辑:程序博客网 时间:2024/04/30 21:13

先看下效果图

这里写图片描述

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<Line> mLines = new ArrayList<Line>(); // 用来记录描述有多少行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<View> mViews = new ArrayList<View>();    // 用来记录每一行有几个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

4 0