整个的原理同 : http://username2.iteye.com/admin/blogs/2229583
直接上代码:
1 ViewGroup 的使用
/** * 个人理解,容器的布局执行过程 1 父容器调用measureChildren 2 子容器调用measure 计算当前容器的宽高和其子容器的宽高 3 * 当前执行的这个子容器触发onMeasure ,设置当前子容器的宽高 4 当前容器调用onLayout , 来展示当前容器的显示 */ public class CustomFlowlayoutContainer extends ViewGroup { public CustomFlowlayoutContainer(Context context) { super(context); } // attrs 是xml中配置的参数会传到这里 public CustomFlowlayoutContainer(Context context, AttributeSet attrs) { super(context, attrs); } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } /** * * 根据父类传入的 widthMeasureSpec和heightMeasureSpec计算本类和其子类的宽高 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 获得它的父容器为它设置的测量模式和大小 int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);//容器的模式为fill_parent或者固定大小,所以这个值为容器宽度 int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // 如果是warp_content情况下,记录宽和高 int width = 0; int height = 0; /** * 记录每一行的宽度,width不断取最大宽度 */ int lineWidth = 0; /** * 每一行的高度,累加至height */ int lineHeight = 0; int cCount = getChildCount(); // 遍历每个子元素 for (int i = 0; i < cCount; i++) { View child = getChildAt(i); // 测量每一个child的宽和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); // 得到child的lp MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); // 当前子控件实际占据的宽度 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; // 当前子控件实际占据的高度 int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; /** * 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行 */ if (lineWidth + childWidth > sizeWidth) { width = Math.max(lineWidth, childWidth);// 取最大的 lineWidth = childWidth; // 重新开启新行,开始记录 // 叠加当前高度, height += lineHeight; // 开启记录下一行的高度 lineHeight = childHeight; } else // 否则累加值lineWidth,lineHeight取最大高度 { lineWidth += childWidth; lineHeight = Math.max(lineHeight, childHeight); } // 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较 if (i == cCount - 1) { width = Math.max(width, lineWidth); height += lineHeight; } } //一般流式布局宽为EXACTLY所以数值为sizeWidth,高为wrap_content 为计算的height setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height); } /** * 存储所有的View,按行记录 */ private List<List<View>> mAllViews = new ArrayList<List<View>>(); /** * 记录每一行的最大高度 */ private List<Integer> mLineHeight = new ArrayList<Integer>(); /** * 对其所有childView进行定位 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //每次布局前要清零 mAllViews.clear(); mLineHeight.clear(); int width = getWidth(); int lineWidth = 0; int lineHeight = 0; // 存储每一行所有的childView List<View> lineViews = new ArrayList<View>(); int cCount = getChildCount(); // 遍历所有的孩子 for (int i = 0; i < cCount; i++) { View child = getChildAt(i); MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); // 如果已经需要换行 if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width) { // 记录这一行所有的View以及最大高度 mLineHeight.add(lineHeight); // 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView mAllViews.add(lineViews); lineWidth = 0;// 重置行宽 lineViews = new ArrayList<View>(); } /** * 如果不需要换行,则累加 */ lineWidth += childWidth + lp.leftMargin + lp.rightMargin; lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin); lineViews.add(child); } // 记录最后一行 mLineHeight.add(lineHeight); mAllViews.add(lineViews); int left = 0; int top = 0; // 得到总行数 int lineNums = mAllViews.size(); for (int i = 0; i < lineNums; i++) { // 每一行的所有的views lineViews = mAllViews.get(i); // 当前行的最大高度 lineHeight = mLineHeight.get(i); Log.e("位置", "第" + i + "行 :" + lineViews.size() + " , " + lineViews); Log.e("位置", "第" + i + "行, :" + lineHeight); // 遍历当前行所有的View for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); if (child.getVisibility() == View.GONE) { continue; } MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); //计算childView的left,top,right,bottom int lc = left + lp.leftMargin; int tc = top + lp.topMargin; int rc =lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); Log.e("位置", child + " , l = " + lc + " , t = " + t + " , r =" + rc + " , b = " + bc); child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin; } left = 0; top += lineHeight; } } }
2 Activity代码
public class TestFlowlayoutActivity extends Activity implements OnClickListener { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_flowlayout ); //DisplayUtil displayUtil = new DisplayUtil(getWindowManager()); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.start: break; default: break; } } }
3 xml 代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#E1E6F6" android:orientation="vertical" > <com.example.fragmentdemo1.widget.CustomFlowlayoutContainer android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="Welcome" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="IT工程师" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="努力啊" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="学习挣钱" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="攒钱娶媳妇了" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="攒钱买房子了" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="攒钱买车子了,什么时候出去玩玩" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:background="@drawable/button_bg" android:text="一辈子就这样没了,该出去休息一下了" /> </com.example.fragmentdemo1.widget.CustomFlowlayoutContainer> </LinearLayout>
4 背景代码button_bg.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 填充色 --> <solid android:color="#FFFFFF" > </solid> <!-- 圆角 --> <corners android:radius="20dp"/> <!-- 描边 --> <stroke android:color="#C9C9C9" android:width="2dp"/> <padding android:bottom="2dp" android:left="10dp" android:right="10dp" android:top="2dp" /> </shape>
相关推荐
微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)...
微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信...
微信小程序——瀑布流布局(截图+源码).zip 微信小程序——瀑布流布局(截图+源码).zip 微信小程序——瀑布流布局(截图+源码).zip 微信小程序——瀑布流布局(截图+源码).zip 微信小程序——瀑布流布局(截图+...
瀑布流布局,又称Masonry布局,是一种常见的网页布局方式,尤其在展示图片或者商品时非常流行。这种布局的特点是每个元素(通常是图片)的宽度不固定,但它们的左侧边缘会对齐,形成一种自适应的错落效果,类似于...
瀑布流布局,也被称为Masonry布局或Pinterest布局,是一种常用于网页和移动应用中的展示大量图像或内容的方式。它的特点是内容以多列的形式排列,每一列的高度不固定,随着页面滚动,新内容会自然地填充到列的底部,...
本教程将通过一个具体的实例——“微信小程序-实现瀑布流布局demo”来探讨如何在微信小程序中实现瀑布流布局和无限下拉加载功能。 首先,我们要理解瀑布流布局。这是一种常见的网页设计布局方式,其特点是以多列...
在这个“微信小程序图片瀑布流布局demo”中,我们将会探讨如何在微信小程序中实现图片的瀑布流展示,这是一种常见的网页和移动应用设计模式,尤其适用于图片分享和展示类应用。 瀑布流布局,又称为无限滚动或荷叶边...
瀑布流布局,也被称为Masonry布局,是一种常用于图片展示或商品列表的网页设计模式,它的特点是元素在页面上自适应地垂直排列,形成一种类似瀑布倾泻的效果。这种布局方式能够有效地利用屏幕空间,使得视觉效果更加...
瀑布流布局,又称为Pinterest布局,是Android应用中一种常见的图片展示方式,因其效果类似瀑布倾泻而下,且图片可以交错排列,视觉效果独特,故得名。这种布局方式在展示图片分享、商品列表等场景中非常流行,能够...
瀑布流布局,也被称为Masonry布局,是一种网页设计布局方式,常见于图片分享网站和电商产品展示页面。这种布局的特点是元素逐行排列,每行中的元素宽度不固定,但高度自适应,使得整体视觉效果像瀑布一样从上至下...
瀑布流布局,又称Masonry布局,是一种常见的网页设计布局方式,尤其在图片展示类网站中广泛应用。这种布局方式模仿了瀑布或流水下落的效果,每一列的元素自上而下依次排列,每列的高度根据其内容自动调整,使得页面...
瀑布流布局在Android应用开发中是一种常见的展示方式,尤其在电商、社交等应用中用于商品或图片的展示。它的特点是视图元素不均匀分布,像瀑布一样从上至下流淌,每一行的列数可能不同,形成一种错落有致的效果。在...
瀑布流是今年流行的一种页面布局方式,淘宝哇喔,蘑菇街,点点等都采用了瀑布流布局。花瓣主题集成了日志一键分享功能,对于提升网站流量非常有用。另外petal对于浏览器的兼容也是不错的,支持目前所有主流浏览器,...
jQuery瀑布流布局是一种常见的网页设计技术,用于展示内容时创建类似瀑布般的多列布局,使得内容在页面上自适应地填充空间,同时保持各元素之间的间距一致。这种布局方式尤其适用于图片展示、商品目录或者博客文章...
瀑布流布局,又称Masonry Layout,是一种常见的网页和移动应用设计模式,特别是在图片展示和电商应用中尤为常见。在Android平台上实现瀑布流布局,能够使内容以美观且适应不同屏幕尺寸的方式排列,用户可以在滚动时...
Web流布局,也被称为“液态布局”或“灵活布局”,是网页设计中的一种布局方式,它允许网页元素根据浏览器窗口大小的变化而自动调整自身尺寸,以保持良好的可读性和用户体验。这种布局模式在响应式网页设计中尤其...
在Android开发中,瀑布流式布局(Waterfall Layout)是一种常见的UI设计模式,它主要用于展示内容丰富的列表,如图片、商品、文章等,通常应用于新闻客户端、电商应用等。这种布局方式模仿了真实世界中瀑布流水的...
瀑布流布局,又称为瀑布流式布局或者无限滚动布局,是一种常见的移动应用和网页设计布局方式,尤其在图片展示和电商应用中非常流行。它的特点在于,内容以多列的形式呈现,每一列中的元素高度不一,使得整体视觉效果...
瀑布流布局(Waterfall Layout),又称流式布局,通常用于展示图片或者商品,这种布局方式使得屏幕空间得到充分利用,视觉效果更加美观。本项目参考着重于在Android Studio环境下如何实现RecyclerView结合瀑布流布局...
根据给定的信息,本文将详细解析瀑布流布局的实现方法,并深入探讨其在网页设计中的应用价值。瀑布流布局是一种非常流行的布局方式,它能够使页面元素像瀑布一样自上而下、从左到右地排列,使得不同高度的内容能够...