Android 流式布局FlowLayout
这个是在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相关推荐
- android 自定义flowlayout,Android 流式布局FlowLayout 实现关键字标签
FlowLayout Android 流式布局FlowLayout 实现关键字标签 效果图 使用方法 在项目根目录的build.gradle文件中加入如下代码 maven { url "ht ...
- Android流式布局FlowLayout,一款针对Tag的布局
交流群 : 668524118 本群主要用于编程技术 ,及创意作品 ,思维架构的交流 ,欢迎喜欢创新 ,热爱生活的朋友加入 ! 前言 flow layout, 流式布局, 这个概念在移动端或者前端开发 ...
- android 流失布局,GitHub - hongyangAndroid/FlowLayout: [不再维护]Android流式布局,支持单选、多选等,适合用于产品标签等。...
FlowLayout Android流式布局,支持单选.多选等,适合用于产品标签等. ##特色 以setAdapter形式注入数据 直接设置selector为background即可完成标签选则的切换 ...
- android分组流式布局,Android 流式布局实现
概述 本文主要分享Android流式布局实现,实现效果如下: 在实现之前先来看一下View的生命周期,如下图: 流式布局属于自定义ViewGroup,重点关注onMeasure与onLayout方法 ...
- 常用的流式布局FlowLayout
流式布局FlowLayout 代码示例: package Test;import javax.swing.*; import java.awt.*;public class FlowLayoutTes ...
- 流式布局FlowLayout支持行数控制,单选,多选,点击等操作
最近有这么一个需求,如下图 开发中内容搜索页面经常会记录搜索关键字,搜索关键字长度不一,我们通过会采用自定义流布局的方式展示:流布局的基本需要是动态添加childView并实现自动换行操作,这个操作比 ...
- Android 流式布局
Android 流式布局 首先目标 最近Android流式布局很火爆,首先我们可以把这一标签页的整体看成一个容器,然后容器内有许多小控件(TextView,Button,ImageView等),再来这 ...
- Android自定义流式布局-FlowLayout
很多App在搜索页时都有对热门标签的一个排列,而Android官方没有对应的布局控件,所以自己写了一个流式布局(也称标签布局)--FlowLayout. 为了大家使用的方便,没有添加自定义属性,所以需 ...
- Android第三方流式布局FlowLayout简单实用(搜索历史记录)
效果图: 导入大Model下: maven { url 'https://jitpack.io' } builde.gradle依赖: implementation 'com.github.LRH19 ...
最新文章
- python timer使用-Python timer定时器两种常用方法解析
- SAP Spartacus not found的页面处理机制
- 浅谈C++类(5)--友元
- 无人机目标定位C++程序
- countdownlatch的使用详解(好懂!!)
- 如何隐藏地址栏中的真实地址_如何删除Chrome地址栏记录?
- 2.3谨慎活跃问题(Beware of Liveness Problems)
- timeshift 安装使用说明
- coolpro2 剪切并淡出
- win7 专业版 破解教程
- Python报错unindent does not match any outer indentation level如何解决?
- 解决python在linux上导包出现no module named ...的问题
- OneDrive彻底卸载
- 名家名言 Chuck Thacker
- 川大计算机学院有哪些专业,四川大学有哪些专业
- Centos7登陆颜色修改#PS1
- Android开发之——卸载系统应用
- 弹弹堂服务器找不到,4399弹弹堂 合服常见问题及解答
- python F5创建pool和创建member(一)
- leetcode 递增的三元子序列