整个的原理同 : 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>
相关推荐
微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)...
微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信...
瀑布流布局,又称Masonry布局,是一种常见的网页布局方式,尤其在展示图片或者商品时非常流行。这种布局的特点是每个元素(通常是图片)的宽度不固定,但它们的左侧边缘会对齐,形成一种自适应的错落效果,类似于...
本教程将通过一个具体的实例——“微信小程序-实现瀑布流布局demo”来探讨如何在微信小程序中实现瀑布流布局和无限下拉加载功能。 首先,我们要理解瀑布流布局。这是一种常见的网页设计布局方式,其特点是以多列...
小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小...
在这个“微信小程序图片瀑布流布局demo”中,我们将会探讨如何在微信小程序中实现图片的瀑布流展示,这是一种常见的网页和移动应用设计模式,尤其适用于图片分享和展示类应用。 瀑布流布局,又称为无限滚动或荷叶边...
瀑布流布局,也被称为Masonry布局,是一种常用于图片展示或商品列表的网页设计模式,它的特点是元素在页面上自适应地垂直排列,形成一种类似瀑布倾泻的效果。这种布局方式能够有效地利用屏幕空间,使得视觉效果更加...
瀑布流布局是一种常见的网页设计模式,它以一种不规则的方式排列元素,使页面看起来像瀑布一样自上而下流动。这种布局方式常用于图片展示、社交媒体应用和电子商务网站,因为它可以提供良好的视觉体验,使用户在浏览...
移动端H5瀑布流布局技术 移动端H5瀑布流布局是一种流行的网页布局方式,视觉上呈现出一种像瀑布一样垂直落下的排版。每张图片并不是显示的正正方方的,而是有的长有的短,呈现出一种不规则的形状。但是它们的宽度...
瀑布流布局,又称Masonry Layout,是一种常见的网页和移动应用界面设计模式,尤其在图片展示、电商产品列表等场景中广泛应用。在Android平台上实现瀑布流布局,可以为用户提供美观且富有动态感的浏览体验。本篇文章...
在Android开发中,瀑布流式布局(Waterfall Layout)是一种常见的UI设计模式,它主要用于展示内容丰富的列表,如图片、商品、文章等,通常应用于新闻客户端、电商应用等。这种布局方式模仿了真实世界中瀑布流水的...
瀑布流布局,又称Masonry布局或Pinterest布局,是一种在网页设计和移动应用中常见的图片展示方式,尤其在图片分享类应用中广泛使用。这种布局方式的特点是将元素以多列的形式排列,每列中的元素间距相等,但各列之间...
瀑布流布局,也被称为Masonry布局,是一种常用于图片展示或网页设计的布局方式,它模仿了瀑布下落的效果,使得页面上的元素可以自适应地排列,每列的高度不固定,根据内容填充。这种布局模式在电子商务网站、社交...
瀑布流布局的多种实现方式及其比较研究 瀑布流布局是指一种网站页面布局方式,通过将内容以瀑布状的形式呈现,提供了良好的用户体验。该布局方式突破了传统网页的布局方式,不仅设计独特,更能带来良好的用户体验,...
【jQuery点击添加图片瀑布流布局效果】是一种常见的前端网页设计技术,主要应用于展示大量图片时,提供美观且高效的浏览体验。瀑布流布局,也被称为Pinterest式布局,因其图像逐个下落并形成类似瀑布的效果而得名。...
瀑布流图片布局是一种常见的网页设计模式,常用于展示图片丰富的网站,如摄影网站、社交媒体或者电商产品展示等。它的特点是图片以多列的形式排列,每一列的高度不固定,随着图片内容的变化而自然下落,形成一种类似...
这篇项目以"swift-用swift写的简单的瀑布流布局用于UICollectionView支持拖拽布局"为标题,意味着它提供了一个实现瀑布流布局的解决方案,并且集成了拖拽功能。在iOS应用开发中,用户交互体验至关重要,拖拽布局能...
瀑布流布局,也被称为Masonry布局,是一种常用于图片展示的网页设计模式,它使得页面中的元素能够像瀑布一样从上到下自然流动,每行的元素宽度不固定,但保持了良好的视觉平衡。在本案例中,我们将讨论如何利用...
在IT领域,瀑布流布局(Masonry Layout)是一种常见的网页设计模式,特别是在图片展示和画廊应用中。这种布局方式可以有效地展示大量的图片,让用户在有限的屏幕空间内看到尽可能多的内容,同时保持视觉上的平衡和...
【jQuery响应式图片瀑布流布局代码】是一种网页设计技术,旨在提供一种动态、美观且适应不同设备屏幕尺寸的图片展示方式。在这个项目中,开发者利用了JavaScript库jQuery的高效特性和响应式设计原理来实现这一功能。...