自定义FlowLayout,android flowLayout实现

举报
再见孙悟空_ 发表于 2022/01/13 23:29:02 2022/01/13
【摘要】 我想大家在开发过程中都碰到过这样的需求,类似标签展示,要展示如上图效果,这里面的数据不确定每项字数,有的非常长,有的很短,数据动态填充。 这种情况用listView和gridView展示效果都没有上图的效果。 这时我们其实是要自己写一个控件来填充上图的数据,也就是我们今天要说的自定义view,流式布局。 方法还是重写onMea...

我想大家在开发过程中都碰到过这样的需求,类似标签展示,要展示如上图效果,这里面的数据不确定每项字数,有的非常长,有的很短,数据动态填充。

这种情况用listView和gridView展示效果都没有上图的效果。

这时我们其实是要自己写一个控件来填充上图的数据,也就是我们今天要说的自定义view,流式布局。

方法还是重写onMeasure和onLayout

话不多说  ,代码贴上

一.自定义view


  
  1. package com.jky.mobilebzt.view;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.content.Context;
  5. import android.util.AttributeSet;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. public class XCFlowLayout extends ViewGroup {
  9. // 存储所有子View
  10. private List<List<View>> mAllChildViews = new ArrayList<List<View>>();
  11. // 每一行的高度
  12. private List<Integer> mLineHeight = new ArrayList<Integer>();
  13. public XCFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  14. super(context, attrs, defStyleAttr);
  15. }
  16. public XCFlowLayout(Context context, AttributeSet attrs) {
  17. this(context, attrs, 0);
  18. }
  19. public XCFlowLayout(Context context) {
  20. this(context, null);
  21. }
  22. @Override
  23. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  24. // TODO Auto-generated method stub
  25. // 父控件传进来的宽度和高度以及对应的测量模式
  26. int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
  27. int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
  28. int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
  29. int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
  30. // 如果当前ViewGroup的宽高为wrap_content的情况
  31. int width = 0; // 自己测量的宽度
  32. int height = 0; // 自己测量的高度
  33. int lineWidth = 0;// 每一行的宽度
  34. int lineHeight = 0; // 每一行的高度
  35. int childCount = getChildCount();// 获取子view的个数
  36. for (int i = 0; i < childCount; i++) {
  37. View child = getChildAt(i);
  38. // 测量子View的宽和高
  39. measureChild(child, widthMeasureSpec, heightMeasureSpec);
  40. // 得到LayoutParams
  41. MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
  42. // 得到子View占据的宽度
  43. int childWidth = child.getMeasuredWidth() + lp.leftMargin
  44. + lp.rightMargin;
  45. // 得到子View占据的高度
  46. int childHeight = child.getMeasuredHeight() + lp.topMargin
  47. + lp.bottomMargin;
  48. if (lineWidth + childWidth > sizeWidth) {// 需要进行换行
  49. width = Math.max(width, lineWidth); // 得到最大宽度
  50. lineWidth = childWidth; // 重置lineWidth
  51. height += lineHeight; // 得到高度
  52. lineHeight = childHeight;// 重置LineHeight
  53. } else {// 不需要进行换行
  54. lineWidth += childWidth;// 叠加行宽
  55. lineHeight = Math.max(lineHeight, childHeight);
  56. }
  57. if (i == childCount - 1) {// 处理最后一个子View的情况
  58. width = Math.max(width, lineWidth);
  59. height += lineHeight;
  60. }
  61. }
  62. // wrapcontent
  63. setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth
  64. : width, modeHeight == MeasureSpec.EXACTLY ? sizeHeight
  65. : height);
  66. // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  67. }
  68. @Override
  69. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  70. // TODO Auto-generated method stub
  71. mAllChildViews.clear();
  72. mLineHeight.clear();
  73. int width = getWidth();// 获取当前ViewGroup宽度
  74. int lineWidth = 0;
  75. int lineHeight = 0;
  76. List<View> lineViews = new ArrayList<View>();// 记录当前行的View
  77. int childCount = getChildCount();
  78. for (int i = 0; i < childCount; i++) {
  79. View child = getChildAt(i);
  80. MarginLayoutParams lp = (MarginLayoutParams) child
  81. .getLayoutParams();
  82. int childWidth = child.getMeasuredWidth();
  83. int childHeight = child.getMeasuredHeight();
  84. // 需要换行
  85. if (lineWidth + childWidth + lp.leftMargin + lp.rightMargin > width) {
  86. mLineHeight.add(lineHeight); // 记录lineHeight
  87. mAllChildViews.add(lineViews); // 记录当前行的Views
  88. // 重置 行的宽高
  89. lineWidth = 0;
  90. lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
  91. // 重置当前行的View集合;
  92. lineViews = new ArrayList<View>();
  93. }
  94. lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
  95. lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
  96. + lp.bottomMargin);
  97. lineViews.add(child);
  98. }
  99. // 处理最后一行
  100. mLineHeight.add(lineHeight);
  101. mAllChildViews.add(lineViews);
  102. // 设置子View的位置
  103. int left = 0;
  104. int top = 0;
  105. // 获取行数
  106. int lineCount = mAllChildViews.size();
  107. for (int i = 0; i < lineCount; i++) {
  108. // 当前行的views和高度
  109. lineViews = mAllChildViews.get(i);
  110. lineHeight = mLineHeight.get(i);
  111. for (int j = 0; j < lineViews.size(); j++) {
  112. View child = lineViews.get(j);
  113. // 判断是否显示
  114. if (child.getVisibility() == View.GONE) {
  115. continue;
  116. }
  117. MarginLayoutParams lp = (MarginLayoutParams) child
  118. .getLayoutParams();
  119. int cLeft = left + lp.leftMargin;
  120. int cTop = top + lp.topMargin;
  121. int cRight = cLeft + child.getMeasuredWidth();
  122. int cBottom = cTop + child.getMeasuredHeight();
  123. // 进行子View进行布局
  124. child.layout(cLeft, cTop, cRight, cBottom);
  125. left += child.getMeasuredWidth() + lp.leftMargin
  126. + lp.rightMargin;
  127. }
  128. left = 0;
  129. top += lineHeight;
  130. }
  131. }
  132. /**
  133. * 与当前ViewGroup对应的LayoutParams
  134. */
  135. @Override
  136. public LayoutParams generateLayoutParams(AttributeSet attrs) {
  137. return new MarginLayoutParams(getContext(), attrs);
  138. }
  139. }

二.xml部分

xml布局中加上这个


  
  1. <com.jky.mobilebzt.view.XCFlowLayout
  2. android:id="@+id/xcf_hot_words"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. android:layout_marginLeft="@dimen/margin_lsmall"
  6. android:layout_marginBottom="@dimen/margin_normal"
  7. android:layout_marginRight="@dimen/margin_normal" />

三.初始化数据部分


  
  1. @SuppressLint("NewApi")
  2. private void initHotWordViews() {
  3. MarginLayoutParams lp = new MarginLayoutParams(
  4. LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
  5. lp.leftMargin = 20;
  6. lp.rightMargin = 20;
  7. lp.topMargin = 8;
  8. lp.bottomMargin = 8;
  9. for (int i = 0; i < hotWords.size(); i++) {
  10. final String hotWord = hotWords.get(i);
  11. TextView view = new TextView(this);
  12. view.setGravity(Gravity.CENTER);
  13. view.setText(hotWords.get(i));
  14. view.setTextColor(Color.BLACK);
  15. view.setBackground(getResources().getDrawable(R.drawable.hot_word_selector));
  16. mFlowLayout.addView(view, lp);
  17. view.setOnClickListener(new OnClickListener() {
  18. @Override
  19. public void onClick(View v) {
  20. }
  21. });
  22. }
  23. }

hotWords就是你要填充的数据集合
 

基本核心的东西就上面这些 ,最上面的图是我的项目里面最后实现的效果图。如果还有其他问题欢迎加入我们的qq群:

开发一群:454430053开发二群:537532956

文章来源: wukong.blog.csdn.net,作者:再见孙悟空_,版权归原作者所有,如需转载,请联系作者。

原文链接:wukong.blog.csdn.net/article/details/72625902

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。