Android中流式布局和热门标签

  1  import java.util.ArrayList;
  2 import java.util.List;
  3 import android.content.Context;
  4 import android.util.AttributeSet;
  5 import android.util.Log;
  6 import android.view.View;
  7 import android.view.ViewGroup;
  8
  9 public class FlowLayout extends ViewGroup {
 10
 11     // 存储所有的View 一行一行的存储
 12     // 比如:一共三行 List就是3。一行有10个那么List<View> 就是10
 13     private List<List<View>> mAllViews = new ArrayList<List<View>>();
 14     // 每一行的高度
 15     private List<Integer> mLineHeight = new ArrayList<Integer>();
 16
 17     // 使用控件,及其实行,而且用了自定义的属性
 18     public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
 19         super(context, attrs, defStyle);
 20         // 这样所有的逻辑就全部可以卸载这个里面去
 21     }
 22
 23     // 用到控件的属性(非自定义)
 24     public FlowLayout(Context context, AttributeSet attrs) {
 25         this(context, attrs, 0); // 调用三个构造参数方法
 26     }
 27
 28     // new一个控件的时候,我们传入一个上下文。
 29     public FlowLayout(Context context) {
 30         this(context, null); // 调用两个构造参数方法
 31     }
 32
 33     @Override
 34     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 35         // 宽度(测量值) 容器的宽度
 36         int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
 37         // 宽度(测量模式)
 38         // modeWidth == MeasureSpec.AT_MOST 用于判断
 39         int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
 40
 41         int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
 42         int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
 43
 44         // wrap_content (自己去计算)
 45         int width = 0;
 46         int height = 0;
 47
 48         // 记录每一行的宽度与高度
 49         int lineWidth = 0;
 50         int lineHeight = 0;
 51
 52         // 得到内部元素的个数
 53         int cCount = getChildCount();
 54
 55         for (int i = 0; i < cCount; i++) {
 56             View child = getChildAt(i);
 57             // 测量子View的宽和高
 58             measureChild(child, widthMeasureSpec, heightMeasureSpec);
 59             // 得到LayoutParams
 60             MarginLayoutParams lp = (MarginLayoutParams) child
 61                     .getLayoutParams();
 62
 63             // 子View占据的宽度
 64             int childWidth = child.getMeasuredWidth() + lp.leftMargin
 65                     + lp.rightMargin;
 66             // 子View占据的高度
 67             int childHeight = child.getMeasuredHeight() + lp.topMargin
 68                     + lp.bottomMargin;
 69
 70             // 换行
 71             // lineWidth:上一行的宽度 + childWidth:当前控件的宽度。
 72             // sizeWidth:当前容器的宽度。
 73             // "  - getPaddingLeft()- getPaddingRight() "
 74             // 是针对 android:padding="20dp"进行的。
 75             if (lineWidth + childWidth > sizeWidth - getPaddingLeft()
 76                     - getPaddingRight()) {
 77                 // 对比得到最大的宽度
 78                 width = Math.max(width, lineWidth);
 79                 // 重置lineWidth
 80                 lineWidth = childWidth;
 81                 // 记录行高
 82                 height += lineHeight;
 83                 lineHeight = childHeight;
 84             } else { // 未换行
 85                 // 叠加行宽
 86                 lineWidth += childWidth;
 87                 // 得到当前行最大的高度
 88                 lineHeight = Math.max(lineHeight, childHeight);
 89             }
 90             // 最后一个控件
 91             if (i == cCount - 1) {
 92                 width = Math.max(lineWidth, width);
 93                 height += lineHeight;
 94             }
 95         }
 96
 97         Log.e("TAG", "sizeWidth = " + sizeWidth);
 98         Log.e("TAG", "sizeHeight = " + sizeHeight);
 99
100         // 判断测量模式
101         // " + getPaddingLeft() + getPaddingRight() "
102         // 是针对 android:padding="20dp"进行的。
103         setMeasuredDimension(
104                 //
105                 modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width
106                         + getPaddingLeft() + getPaddingRight(),
107                 modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height
108                         + getPaddingTop() + getPaddingBottom()//
109         );
110
111     }
112
113     @Override
114     protected void onLayout(boolean changed, int l, int t, int r, int b) {
115         mAllViews.clear();
116         mLineHeight.clear();
117
118         // 当前ViewGroup的宽度
119         int width = getWidth();
120
121         int lineWidth = 0;
122         int lineHeight = 0;
123
124         List<View> lineViews = new ArrayList<View>();
125
126         int cCount = getChildCount();
127
128         for (int i = 0; i < cCount; i++) {
129             View child = getChildAt(i);
130             MarginLayoutParams lp = (MarginLayoutParams) child
131                     .getLayoutParams();
132
133             int childWidth = child.getMeasuredWidth();
134             int childHeight = child.getMeasuredHeight();
135
136             // 如果需要换行
137             // 当前行的宽度 + 当前列的宽度 + lp.leftMargin + lp.rightMargin
138             // " - getPaddingLeft() - getPaddingRight() "
139             // 是针对 android:padding="20dp"进行的。
140             if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width
141                     - getPaddingLeft() - getPaddingRight()) {
142                 // 记录LineHeight
143                 mLineHeight.add(lineHeight);
144                 // 记录当前行的Views
145                 mAllViews.add(lineViews);
146
147                 // 重置我们的行宽和行高
148                 lineWidth = 0;
149                 lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
150                 // 重置我们的View集合
151                 lineViews = new ArrayList<View>();
152             }
153             lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
154             lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
155                     + lp.bottomMargin);
156             lineViews.add(child);
157
158         }// for end
159             // 处理最后一行
160         mLineHeight.add(lineHeight);
161         mAllViews.add(lineViews);
162
163         // 设置子View的位置
164         // 是针对 android:padding进行的。
165         // 所以不能给left和top设置0。
166         int left = getPaddingLeft();
167         int top = getPaddingTop();
168
169         // 行数
170         int lineNum = mAllViews.size();
171
172         for (int i = 0; i < lineNum; i++) {
173             // 当前行的所有的View
174             lineViews = mAllViews.get(i);
175             lineHeight = mLineHeight.get(i);
176
177             for (int j = 0; j < lineViews.size(); j++) {
178                 View child = lineViews.get(j);
179                 // 判断child的状态
180                 if (child.getVisibility() == View.GONE) {
181                     continue;
182                 }
183
184                 MarginLayoutParams lp = (MarginLayoutParams) child
185                         .getLayoutParams();
186
187                 int lc = left + lp.leftMargin;
188                 int tc = top + lp.topMargin;
189                 int rc = lc + child.getMeasuredWidth();
190                 int bc = tc + child.getMeasuredHeight();
191
192                 // 为子View进行布局
193                 child.layout(lc, tc, rc, bc);
194
195                 left += child.getMeasuredWidth() + lp.leftMargin
196                         + lp.rightMargin;
197             }
198             // 每次循环完一行后
199             // 是针对 android:padding进行的。
200             // 所以不能给left设置0。
201             left = getPaddingLeft();
202             top += lineHeight; // 累加
203         }
204
205     }
206
207     /**
208      * 与当前ViewGroup对应的LayoutParams
209      */
210     @Override
211     public LayoutParams generateLayoutParams(AttributeSet attrs) {
212         return new MarginLayoutParams(getContext(), attrs);
213     }
214
215 }
<RelativeLayout 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" >

    <com.imooc.view.FlowLayout
        android:id="@+id/id_flowlayout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#E5E5F5"
        android:padding="20dp" >
    </com.imooc.view.FlowLayout>

</RelativeLayout>
 1 import android.app.Activity;
 2 import android.os.Bundle;
 3 import android.view.LayoutInflater;
 4 import android.widget.TextView;
 5
 6 import com.imooc.view.FlowLayout;
 7
 8 public class MainActivity extends Activity {
 9
10     private String[] mVals = new String[] { "Hello", "Android", "Weclome Hi ",
11             "Button", "TextView", "Hello", "Android", "Weclome",
12             "Button ImageView", "TextView", "Helloworld", "Android",
13             "Weclome Hello", "Button Text", "TextView" };
14
15     private FlowLayout mFlowLayout;
16
17     @Override
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20
21         setContentView(R.layout.activity_main);
22
23         mFlowLayout = (FlowLayout) findViewById(R.id.id_flowlayout);
24
25         initData();
26     }
27
28     public void initData() {
29         // for (int i = 0; i < mVals.length; i++)
30         // {
31         // Button btn = new Button(this);
32         //
33         // MarginLayoutParams lp = new MarginLayoutParams(
34         // MarginLayoutParams.WRAP_CONTENT,
35         // MarginLayoutParams.WRAP_CONTENT);
36         //
37         // btn.setText(mVals[i]);
38         // mFlowLayout.addView(btn, lp);
39         // }
40         LayoutInflater mInflater = LayoutInflater.from(this);
41         for (int i = 0; i < mVals.length; i++) {
42             TextView tv = (TextView) mInflater.inflate(R.layout.tv,
43                     mFlowLayout, false);
44             tv.setText(mVals[i]);
45             mFlowLayout.addView(tv);
46         }
47
48     }
49
50 }
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="wrap_content"
 4     android:layout_height="wrap_content"
 5     android:layout_margin="5dp"
 6     android:background="@drawable/tv_bg"
 7     android:textColor="#5BC4ED"
 8     android:text="Helloworld" >
 9
10 </TextView>

@drawable/tv_bg

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <shape xmlns:android="http://schemas.android.com/apk/res/android" >
 3     <solid android:color="#ffffff" />
 4     <corners android:radius="30dp" />
 5     <padding
 6         android:bottom="2dp"
 7         android:left="10dp"
 8         android:right="10dp"
 9         android:top="2dp" />
10 </shape>

DEMO下载地址:

时间: 2024-08-01 00:06:25

Android中流式布局和热门标签的相关文章

android流式布局热门标签的实现

在日常的app使用中,我们会在android 的app中看见热门标签等自动换行的流式布局,今天就为大家分享一种android流式布局的实现. 先看最终效果 自定义流式布局的实现 package com.sunny.flowlayout.view; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.util.AttributeSet; import an

Android流式布局实现

查看我的全部开源项目[开源实验室] 欢迎加入我的QQ群:[201055521],本博客客户端下载[请点击] 摘要 新项目用到了一种全新布局----Android标签流式布局的功能,正好一直说给大家讲自定义控件的实现,今天就为大家讲一种android流式布局的实现. 本文原创,转载请注明地址:http://blog.kymjs.com/ 正文 在日常的app使用中,我们会在android 的app中看见热门标签等自动换行的流式布局,今天,我们就来看看如何自定义一个类似热门标签那样的流式布局吧(源码

android -------- 流式布局,支持单选、多选等

最近开发中有流式标签这个功能,网上学了下,来分享一下 Android 流式布局,支持单选.多选等,适合用于产品标签等. 效果图: 用法: dependencies { compile 'com.hyman:flowlayout-lib:1.1.2' } 布局: <!--max_select:-1为不限制选择数量,>=1的数字为控制选择tag的数量--> <com.zhy.view.flowlayout.TagFlowLayout android:id="@+id/id_f

含有过滤功能的android流式布局

FilterFlowLayout 含有过滤功能的流式布局, 参考FlowLayout 可以去除宽度不在范围(比例或真实值)内的子view 可以设置最大行数 可以添加组件间水平间距 可以添加行间距 系统要求 Android 4.0以上 快速使用 <me.codeboy.android.lib.FilterFlowLayout xmlns:cb="http://schemas.android.com/apk/res-auto" android:id="@+id/filter

谷歌推出Android 响应式布局控件 FlexboxLayout -盒子模型

今天github 排行榜上突然出现了 谷歌最新推出的Android 最新控件FlexboxLayout . FlexboxLayout 究竟是什么东西呢? fexbox 也称为盒子模型,广泛用于前端开发,做过前端 web 的都知道Bootstrap 中有一套强大的 CSS 网格样式. Bootstrap 的出现 大大提高了前端开发的效率,并且引领了响应式布局.跨平台开发的潮流. FlexboxLayout  就是类似于 bootstrap 中见网格系统的 强大控件 先上几张谷歌示例程序的截图 F

android 自定义流布局。实现热门标签。开源库SimpleFlowLayout

前言 实际项目中需要实现一个 热门搜索 的栏目,类似下图: 由于 子项(子view) 中的文字是可变的,一行能显示的 子项 的个数也无法确定.需要支持自动换行和计算位置. 开源类库 我自己写了个 自定义view ,继承自viewGroup, 来实现它,托管到github开源平台. 名称:SimpleFlowLayout 地址:https://github.com/vir56k/SimpleFlowLayout 特点:可以不断添加多个子view,计算位置,自动换行. 类似html中的div标签 适

android流式布局:FlexboxLayout用法探析(一)

FlexboxLayout是google官方开源的一个可以简单快速创建具有弹性功能的流式布局,它的目的是使用我们常见的布局模式,帮我们很好的实现UI区域的比例划分,比如三列布局,可以非常简单的实现.它支持非常多的属性设置,用起来很简单. GitHub:https://github.com/google/flexbox-layout 首先引入该库: dependencies { compile 'com.google.android:flexbox:0.2.2' } 然后是在布局文件中声明使用该控

Android中常见的热门标签的流式布局的实现

一.概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出) 类似的自定义布局.下面我们就来详细介绍流式布局的应用特点以及用的的技术点: 1.流式布局的特点以及应用场景    特点:当上面一行的空间不够容纳新的TextView时候,    才开辟下一行的空间 原理图: 场景:主要用于关键词搜索或者热门标签等场景2.自定义ViewGroup,重点重写下面两个方法 1.o

html5 响应式布局

响应式布局 第一:正确理解响应式布局 响应式网页设计就是一个网站能够兼容多个终端-而不是为每个终端做一个特定的版本.打个比方来说:现在社会有很多响应产品,例如折叠沙发,折叠床等等,当我们需要把沙发放到一个角落的时候,此刻沙发就好比div吧,而角落里的某个地方就好比父元素,由于父元素空间的改变,我们不得不调整div,让它能够依然放在角落里.在项目中你会遇到不同的终端,由于终端分辨率不同,所以你要想让用户体验更好,就必要让你的页面能够兼容多个终端. 第二:响应式设计的步骤 响应式设计的步骤就是1.编