这个是在GitHub上看到的,GitHub地址:https://github.com/blazsolar/FlowLayout

用FlowLayout方便了很多,这是一个很强大的自定义控件,向原作者致敬,下面先放两张我项目中的两张效果图

                      

第一张图在个性标签处用了FlowLayout,第二张图在添加头像处用到了FlowLayout,好了,进入正题

主要用到里边的FlowLayout.java类

package com.wanglai.widget;import java.util.ArrayList;
import java.util.List;import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;import com.wanglai.main.R;/*** FlowLayout will arrange child elements horizontally one next to another. If there is not enough* space for next view new line will be added.* FlowLayout会水平排列子元素,当一行的空间不足时,将添加新行* User: Blaz Solar* Date: 5/6/13* Time: 8:17 PM*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class FlowLayout extends ViewGroup {private int mGravity = (isIcs() ? Gravity.START : Gravity.LEFT) | Gravity.TOP;private final List<List<View>> mLines = new ArrayList<List<View>>();private final List<Integer> mLineHeights = new ArrayList<Integer>();private final List<Integer> mLineMargins = new ArrayList<Integer>();public FlowLayout(Context context) {this(context, null);}public FlowLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public FlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);/* 绑定values/attrs.xml里面定义的属性*/TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.FlowLayout, defStyle, 0);try {int index = a.getInt(R.styleable.FlowLayout_android_gravity, -1);if(index > 0) {setGravity(index);}} finally {/*至此属性绑定成功*/a.recycle();}}/*** {@inheritDoc}*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);int modeWidth = MeasureSpec.getMode(widthMeasureSpec);int modeHeight = MeasureSpec.getMode(heightMeasureSpec);int width = 0;int height = getPaddingTop() + getPaddingBottom();int lineWidth = 0;int lineHeight = 0;int childCount = getChildCount();for(int i = 0; i < childCount; i++) {View child = getChildAt(i);boolean lastChild = i == childCount - 1;if(child.getVisibility() == View.GONE) {if(lastChild) {width = Math.max(width, lineWidth);height += lineHeight;}continue;}measureChildWithMargins(child, widthMeasureSpec, lineWidth, heightMeasureSpec, height);LayoutParams lp = (LayoutParams) child.getLayoutParams();int childWidthMode = MeasureSpec.AT_MOST;int childWidthSize = sizeWidth;int childHeightMode = MeasureSpec.AT_MOST;int childHeightSize = sizeHeight;if(lp.width == LayoutParams.MATCH_PARENT) {childWidthMode = MeasureSpec.EXACTLY    ;childWidthSize -= lp.leftMargin + lp.rightMargin;} else if(lp.width >= 0) {childWidthMode = MeasureSpec.EXACTLY;childWidthSize = lp.width;}if(lp.height >= 0) {childHeightMode = MeasureSpec.EXACTLY;childHeightSize = lp.height;} else if (modeHeight == MeasureSpec.UNSPECIFIED) {childHeightMode = MeasureSpec.UNSPECIFIED;childHeightSize = 0;}child.measure(MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode),MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode));int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;if(lineWidth + childWidth > sizeWidth) {width = Math.max(width, lineWidth);lineWidth = childWidth;height += lineHeight;lineHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;} else {lineWidth += childWidth;lineHeight = Math.max(lineHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);}if(lastChild) {width = Math.max(width, lineWidth);height += lineHeight;}}width += getPaddingLeft() + getPaddingRight();setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width,(modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height);}/*** {@inheritDoc}*/@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mLines.clear();mLineHeights.clear();mLineMargins.clear();int width = getWidth();int height = getHeight();int linesSum = getPaddingTop();int lineWidth = 0;int lineHeight = 0;List<View> lineViews = new ArrayList<View>();float horizontalGravityFactor;switch ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK)) {case Gravity.LEFT:default:horizontalGravityFactor = 0;break;case Gravity.CENTER_HORIZONTAL:horizontalGravityFactor = .5f;break;case Gravity.RIGHT:horizontalGravityFactor = 1;break;}for(int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);if(child.getVisibility() == View.GONE) {continue;}LayoutParams lp = (LayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;int childHeight = child.getMeasuredHeight() + lp.bottomMargin + lp.topMargin;if(lineWidth + childWidth > width) {mLineHeights.add(lineHeight);mLines.add(lineViews);mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft());linesSum += lineHeight;lineHeight = 0;lineWidth = 0;lineViews = new ArrayList<View>();}lineWidth += childWidth;lineHeight = Math.max(lineHeight, childHeight);lineViews.add(child);}mLineHeights.add(lineHeight);mLines.add(lineViews);mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft());linesSum += lineHeight;int verticalGravityMargin = 0;switch ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) ) {case Gravity.TOP:default:break;case Gravity.CENTER_VERTICAL:verticalGravityMargin = (height - linesSum) / 2;break;case Gravity.BOTTOM:verticalGravityMargin = height - linesSum;break;}int numLines = mLines.size();int left;int top = getPaddingTop();for(int i = 0; i < numLines; i++) {lineHeight = mLineHeights.get(i);lineViews = mLines.get(i);left = mLineMargins.get(i);int children = lineViews.size();for(int j = 0; j < children; j++) {View child = lineViews.get(j);if(child.getVisibility() == View.GONE) {continue;}LayoutParams lp = (LayoutParams) child.getLayoutParams();// if height is match_parent we need to remeasure child to line heightif(lp.height == LayoutParams.MATCH_PARENT) {int childWidthMode = MeasureSpec.AT_MOST;int childWidthSize = lineWidth;if(lp.width == LayoutParams.MATCH_PARENT) {childWidthMode = MeasureSpec.EXACTLY;} else if(lp.width >= 0) {childWidthMode = MeasureSpec.EXACTLY;childWidthSize = lp.width;}child.measure(MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode),MeasureSpec.makeMeasureSpec(lineHeight - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY));}int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();int gravityMargin = 0;if(Gravity.isVertical(lp.gravity)) {switch (lp.gravity) {case Gravity.TOP:default:break;case Gravity.CENTER_VERTICAL:case Gravity.CENTER:gravityMargin = (lineHeight - childHeight - lp.topMargin - lp.bottomMargin) / 2 ;break;case Gravity.BOTTOM:gravityMargin = lineHeight - childHeight - lp.topMargin - lp.bottomMargin;break;}}child.layout(left + lp.leftMargin,top + lp.topMargin + gravityMargin + verticalGravityMargin,left + childWidth + lp.leftMargin,top + childHeight + lp.topMargin + gravityMargin + verticalGravityMargin);left += childWidth + lp.leftMargin + lp.rightMargin;}top += lineHeight;}}@Overrideprotected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {return new LayoutParams(p);}/*** {@inheritDoc}*/@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new LayoutParams(getContext(), attrs);}/*** {@inheritDoc}*/@Overrideprotected LayoutParams generateDefaultLayoutParams() {return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);}@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)public void setGravity(int gravity) {if(mGravity != gravity) {if((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {gravity |= isIcs() ? Gravity.START : Gravity.LEFT;}if((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {gravity |= Gravity.TOP;}mGravity = gravity;requestLayout();}}public int getGravity() {return mGravity;}/*** @return <code>true</code> if device is running ICS or grater version of Android.*/private static boolean isIcs() {return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;}public static class LayoutParams extends MarginLayoutParams {public int gravity = -1;public LayoutParams(Context c, AttributeSet attrs) {super(c, attrs);TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout);try {gravity = a.getInt(R.styleable.FlowLayout_Layout_android_layout_gravity, -1);} finally {a.recycle();}}public LayoutParams(int width, int height) {super(width, height);}public LayoutParams(ViewGroup.LayoutParams source) {super(source);}}}

接下来就是在attrs.xml中加入相应的属性代码:

<declare-styleable name="FlowLayout"><attr name="android:gravity" /></declare-styleable><declare-styleable name="FlowLayout_Layout"><attr name="android:layout_gravity" /></declare-styleable>

现在就可以用到你的项目中了:

<com.wanglai.widget.FlowLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/save_signature_layout"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/baidi"android:gravity="start|top" ><LinearLayoutstyle="@style/label_style"android:background="@drawable/text_shape_yellow"android:orientation="horizontal" ><TextViewstyle="@style/label_text_style"android:text="这是标签"android:textColor="@color/listselect" /><TextViewstyle="@style/label_text_style"android:text="5"android:textColor="@color/listselect" /></LinearLayout><!-- 这里可以加入更多的子元素 --></com.wanglai.widget.FlowLayout>

当然,你也可以在java代码中动态添加子元素:

for(int k = 0;k<phonesUserDtos.size();k++){PhonesUserDto pDto = phonesUserDtos.get(k);//初始化子布局View view = LayoutInflater.from(this).inflate(R.layout.wishtop_item, null);FlowLayout.LayoutParams params = new FlowLayout.LayoutParams(150, 170);view.setLayoutParams(params);params.topMargin = 10;view.setPadding(14, 0, 14, 0);RoundImageView riView = (RoundImageView) view.findViewById(R.id.wishtop_headImage);TextView tView = (TextView) view.findViewById(R.id.wishtop_tv_price);riView.setVisibility(View.VISIBLE);tView.setVisibility(View.VISIBLE);String wishTopHead =pDto.getHeadImage();if (wishTopHead != null && !"".equals(wishTopHead)) {bitmapUtils.configDefaultLoadingImage(R.drawable.touxiang1);bitmapUtils.configDefaultLoadFailedImage(R.drawable.touxiang1);bitmapUtils.display(riView, Constant.AUTO_IMAGE_PATH + wishTopHead);}tView.setText(pDto.getRealname() + "");sb.append(",").append(pDto.getUsername());square_save_img_layout_wai.addView(view,0);
}

ok!是不是很简单呢。自己也是正在学习中,如果有什么不对的地方,欢迎指正

转载请注明出处

Android 流式布局FlowLayout相关推荐

  1. android 自定义flowlayout,Android 流式布局FlowLayout 实现关键字标签

    FlowLayout Android 流式布局FlowLayout 实现关键字标签 效果图 使用方法 在项目根目录的build.gradle文件中加入如下代码 maven { url "ht ...

  2. Android流式布局FlowLayout,一款针对Tag的布局

    交流群 : 668524118 本群主要用于编程技术 ,及创意作品 ,思维架构的交流 ,欢迎喜欢创新 ,热爱生活的朋友加入 ! 前言 flow layout, 流式布局, 这个概念在移动端或者前端开发 ...

  3. android 流失布局,GitHub - hongyangAndroid/FlowLayout: [不再维护]Android流式布局,支持单选、多选等,适合用于产品标签等。...

    FlowLayout Android流式布局,支持单选.多选等,适合用于产品标签等. ##特色 以setAdapter形式注入数据 直接设置selector为background即可完成标签选则的切换 ...

  4. android分组流式布局,Android 流式布局实现

    概述 本文主要分享Android流式布局实现,实现效果如下: 在实现之前先来看一下View的生命周期,如下图: 流式布局属于自定义ViewGroup,重点关注onMeasure与onLayout方法 ...

  5. 常用的流式布局FlowLayout

    流式布局FlowLayout 代码示例: package Test;import javax.swing.*; import java.awt.*;public class FlowLayoutTes ...

  6. 流式布局FlowLayout支持行数控制,单选,多选,点击等操作

    最近有这么一个需求,如下图 开发中内容搜索页面经常会记录搜索关键字,搜索关键字长度不一,我们通过会采用自定义流布局的方式展示:流布局的基本需要是动态添加childView并实现自动换行操作,这个操作比 ...

  7. Android 流式布局

    Android 流式布局 首先目标 最近Android流式布局很火爆,首先我们可以把这一标签页的整体看成一个容器,然后容器内有许多小控件(TextView,Button,ImageView等),再来这 ...

  8. Android自定义流式布局-FlowLayout

    很多App在搜索页时都有对热门标签的一个排列,而Android官方没有对应的布局控件,所以自己写了一个流式布局(也称标签布局)--FlowLayout. 为了大家使用的方便,没有添加自定义属性,所以需 ...

  9. Android第三方流式布局FlowLayout简单实用(搜索历史记录)

    效果图: 导入大Model下: maven { url 'https://jitpack.io' } builde.gradle依赖: implementation 'com.github.LRH19 ...

最新文章

  1. python timer使用-Python timer定时器两种常用方法解析
  2. SAP Spartacus not found的页面处理机制
  3. 浅谈C++类(5)--友元
  4. 无人机目标定位C++程序
  5. countdownlatch的使用详解(好懂!!)
  6. 如何隐藏地址栏中的真实地址_如何删除Chrome地址栏记录?
  7. 2.3谨慎活跃问题(Beware of Liveness Problems)
  8. timeshift 安装使用说明
  9. coolpro2 剪切并淡出
  10. win7 专业版 破解教程
  11. Python报错unindent does not match any outer indentation level如何解决?
  12. 解决python在linux上导包出现no module named ...的问题
  13. OneDrive彻底卸载
  14. 名家名言 Chuck Thacker
  15. 川大计算机学院有哪些专业,四川大学有哪些专业
  16. Centos7登陆颜色修改#PS1
  17. Android开发之——卸载系统应用
  18. 弹弹堂服务器找不到,4399弹弹堂 合服常见问题及解答
  19. python F5创建pool和创建member(一)
  20. leetcode 递增的三元子序列

热门文章

  1. [css] CSS画一个三角形,CSS绘制空心三角形
  2. Mac上如何降级系统?Mac系统降级图文教程
  3. 【GStreamer】基于NTP+SEI的视频流传输时延测量
  4. python 微信机器人 关键词_python-微信机器人之词云
  5. 你会给父母买保险吗?
  6. 书评与摘抄《白鹿原》
  7. App渠道统计方法全面解析 总有一种适合你
  8. Vue生命周期总结(四个阶段,八个钩子函数)
  9. linux 英语翻译软件下载,英语翻译神器下载
  10. 安全多方计算技术介绍