实现代码

public class FlowLayout extends ViewGroup {private List<Line> mLines = new ArrayList<Line>(); // 用来记录描述有多少行Viewprivate Line mCurrrenLine;                      // 用来记录当前已经添加到了哪一行private int mHorizontalSpace = 10;private int mVerticalSpace = 10;public FlowLayout(Context context, AttributeSet attrs) {super(context, attrs);}public FlowLayout(Context context) {super(context);}public void setSpace(int horizontalSpace, int verticalSpace) {this.mHorizontalSpace = horizontalSpace;this.mVerticalSpace = verticalSpace;}@Overrideprotected 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 view = getChildAt(i);// 如果孩子不可见if (view.getVisibility() == View.GONE) {continue;}// 测量孩子measureChild(view, widthMeasureSpec, heightMeasureSpec);// 往lines添加孩子if (mCurrrenLine == null) {// 说明还没有开始添加孩子mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);// 添加到 Lines中mLines.add(mCurrrenLine);// 行中一个孩子都没有mCurrrenLine.addView(view);} else {// 行不为空,行中有孩子了boolean canAdd = mCurrrenLine.canAdd(view);if (canAdd) {// 可以添加mCurrrenLine.addView(view);} else {// 不可以添加,装不下去// 换行// 新建行mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);// 添加到lines中mLines.add(mCurrrenLine);// 将view添加到linemCurrrenLine.addView(view);}}}// 设置自己的宽度和高度int measuredWidth = layoutWidth;// paddingTop + paddingBottom + 所有的行间距 + 所有的行的高度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);}@Overrideprotected 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>();    // 用来记录每一行有几个Viewprivate 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) {// 说还没有添加Viewif (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) {// 判断是否能添加Viewint 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) {// 改变宽度,View的长度改变了,需要重新measureint 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;}}}}
public class FlowActivity extends AppCompatActivity {private ScrollView mScrollView;private FlowLayout mFlowLayout;private List<String> mData;private Gson mGson;private String appname = "['QQ','视频','京东','youni有你','万年历-农历黄历','支付宝钱包']";@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);initData();initView();}private void initData() {mGson = new Gson();mData = mGson.fromJson(appname,new TypeToken<List<String>>(){}.getType());}private void initView() {setContentView(mScrollView = new ScrollView(this));SpannableString title = new SpannableString("流式布局,热门标签");title.setSpan(new ForegroundColorSpan(Color.WHITE),0,title.length(),Spannable.SPAN_INCLUSIVE_EXCLUSIVE);ActionBar actionBar = getSupportActionBar();actionBar.setTitle(title);mScrollView.setBackgroundColor(Color.parseColor("#eaeaea"));mScrollView.setVerticalScrollBarEnabled(false);mFlowLayout = new FlowLayout(this);int padding = UIUtil.dip2px(15);mFlowLayout.setPadding(UIUtil.dip2px(10), padding, UIUtil.dip2px(10), padding);mFlowLayout.setSpace(UIUtil.dip2px(10), UIUtil.dip2px(15));for (final String data : mData) {TextView textView = new TextView(this);int tvPadding = UIUtil.dip2px(10);textView.setPadding(UIUtil.dip2px(15), tvPadding, UIUtil.dip2px(15), tvPadding);textView.setGravity(Gravity.CENTER);textView.setTextSize(16);textView.setText(data);textView.setTextColor(Color.WHITE);Random random = new Random();//Math.random()int alpha = 255;int green = random.nextInt(190) + 30;int red = random.nextInt(190) + 30;int blue = random.nextInt(190) + 30;int argb = Color.argb(alpha, red, green, blue);//设置shapeGradientDrawable normalDrawable = new GradientDrawable();normalDrawable.setCornerRadius(UIUtil.dip2px(6));normalDrawable.setColor(argb);GradientDrawable pressedDrawable = new GradientDrawable();pressedDrawable.setColor(Color.DKGRAY);pressedDrawable.setCornerRadius(UIUtil.dip2px(5));//设置选择器selectorStateListDrawable stateListDrawable = new StateListDrawable();stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);stateListDrawable.addState(new int[]{}, normalDrawable);textView.setBackgroundDrawable(stateListDrawable);textView.setClickable(true);textView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ToastUtil.toast(data);}});mFlowLayout.addView(textView);}mScrollView.addView(mFlowLayout);}
}

自定义控件:流式布局相关推荐

  1. 自定义控件 - 流式布局(CofferFlowLayout)

    自定义控件 - 流式布局(CofferFlowLayout) 先看效果图: 简介 为了方便大家理解自定义View里的一些细节点,我这里把开发者模式里的"显示布局边界"打开了.这个D ...

  2. 自定义控件 流式布局

    自定义控件 流式布局 package com.example.layout;import android.content.Context; import android.content.res.Typ ...

  3. 自定义控件 - 流式布局:TagFlowLayout

    在项目中需要用到流式布局的样式,此文学习鸿洋大神的FlowLayout控件,学习使用一下.出自 http://blog.csdn.net/lmj623565791/article/details/38 ...

  4. 自定义控件 - 流式布局(FlowLayout)

    效果图 item 布局文件kingoit_flow_layout <?xml version="1.0" encoding="utf-8"?> &l ...

  5. 自定义 FlowLayout流式布局搜索框 加 GreenDao存取搜索记录,使用RecyclerView展示

    输入框布局的shape <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android ...

  6. Android自定义控件之流式布局

    效果图: 一.首先创建我 们的自定义流式布局 public class FlowLayoutView extends ViewGroup {public FlowLayoutView(Context ...

  7. android自定义流式布局思路,Android 自定义控件基础-流式布局

    什么是流式布局?其实我们在平时遇到过,只是有可能叫不出它的名字. 如图: 如上图,就是一个流式布局的样式. &esmp;这里,将记录一下怎么实现这个功能.其实实现这个功能的方法,就是自定义Vi ...

  8. 自定义View----滑动刻度尺与流式布局 实例(四)

    2019独角兽企业重金招聘Python工程师标准>>> 近在系统学习自定义View这一块的知识,前面几篇基本都是理论知识,这篇博客着重从实战来加强对自定义View的理解与运用.实现的 ...

  9. Android FlowLayout流式布局

    最近使用APP的时候经常看到有 这种流式布局 ,今天我就跟大家一起来动手撸一个这种自定义控件. 首先说一下自定义控件的流程: 自定义控件一般要么继承View要么继承ViewGroup View的自定义 ...

最新文章

  1. 95页重磅报告:全面预测未来5年趋势
  2. Hi3516A开发--ethtool安装和使用
  3. android后台截屏实现(3)--编译screencap
  4. 某房产中介服务器托管及安全方案(下)
  5. php流导出excel内存溢出,phpExcel导出大量数据出现内存溢出错误的解决方法
  6. CSS精粹之布局技巧
  7. 国外的老师是怎么教Golang的?
  8. java后台代码添加超链接_Java 添加超链接至Excel文档
  9. Linux搭建局域网邮箱服务器,菜鸟搭建开源的局域网邮件服务器-windows linux均适用...
  10. 第四方支付跟第三方支付的区别,支付源码有什么用
  11. 2.4G wifi 的频道/信道 20M 40M的概念
  12. GPU/CPU性能天梯图
  13. 路由器/交换机flow 调试指令
  14. 27岁了,目前从事软件测试,听一些说测试前途是IT里最差的,是这样吗
  15. 计算机不能进入桌面,电脑开机后进不了桌面,详细教您电脑开机后无法进入桌面怎么办...
  16. cs python课程 加州大学_【北美名校CS课程整理系列】10. 数据结构与算法分析
  17. 使用apache服务部署静态网站--初篇
  18. 淘宝店铺怎么升级到一钻?方法是什么?
  19. pyc和py文件的区别
  20. Netty 支持哪些常用的解码器?

热门文章

  1. 什么是物理层接口?—Vecloud 微云
  2. css实现文字在横线上居中
  3. java 之 继承 super关键籽 this关键字 final关键字
  4. Anaconda 环境下 对Tushare进行测试
  5. [译文]c#扩展方法(Extension Method In C#)
  6. hdu 5903 Square Distance
  7. 使用C#程序处理PowerPoint文件中的字符串
  8. Java 8特性有望进入.Net/Mono
  9. 让你的AIR程序脱离AIR环境运行
  10. AJAX ControlToolkit学习日志-ResizableControlExtender(23)