(四)UI绘制流程-瀑布流布局
来源:互联网 发布:宝软网java破解游戏 编辑:程序博客网 时间:2024/05/21 21:49
版权声明:本文为博主原创文章,未经博主允许不得转载。
本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。
一.前言
上一篇给出了流式布局,这里再来一篇瀑布流布局练手,同时代码稍微简洁一些。不再利用封装类来保存数据,直接把子 View 的四个边沿保存在对应的 LayoutParams 中。
二、分析
1.generateLayoutParams()获取封装子 View 的左上右下四个边沿的自定义 WaterfallLayoutParams。
2.onMeasure() 测量自身宽高的同时把在子 View 的 LayoutParams 存储该子 View 对应的四个边沿值。
3.onLayout()把每行 View 进行摆放。
三、实现
1.自定义的 LayoutParams
//WaterfallLayout 下的子控件的布局,保存该控件的左上右下四个边沿值 public static class WaterfallLayoutParams extends ViewGroup.LayoutParams { public int left = 0; public int top = 0; public int right = 0; public int bottom = 0; public WaterfallLayoutParams(Context context, AttributeSet attrs) { super(context, attrs); } public WaterfallLayoutParams(int width, int height) { super(width, height); } public WaterfallLayoutParams(android.view.ViewGroup.LayoutParams params) { super(params); } }
二、generateLayoutParams()
由于使用了自定义的 LayoutParams,这里必须全部写出以下方法,不然会报强转错误,这边只是展示有这么个用法,自定义 LayoutParams 就暂时不在这边记录。
@Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new WaterfallLayoutParams(getContext(), attrs); } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new WaterfallLayoutParams(WaterfallLayoutParams.WRAP_CONTENT, WaterfallLayoutParams.WRAP_CONTENT); } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new WaterfallLayoutParams(p); } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof WaterfallLayoutParams; }
三、onMeasure()
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //获取父容器为 WaterfallLayout 设置的测量模式和大小的建议值 int iWidthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int iHeightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int iWidthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int iHeightSpecSize = MeasureSpec.getSize(heightMeasureSpec); //记录测量的宽高 int measuredWith = 0; int measuredHeight = 0; //计算列的宽度 columnWidth = (iWidthSpecSize - mVerticalSpace * (columnCount - 1)) / columnCount; //获取子 View 的数量 int childCount = getChildCount(); //如果不满一排,测量宽度为一排的实际宽度 if (childCount < columnCount) { measuredWith = childCount * (columnWidth + mHorizontalSpace) - mHorizontalSpace; } else { measuredWith = iWidthSpecSize; } //循环遍历子 View,进行子 View 的测量以及 WaterfallLayout 宽高的计算 for (int i=0; i<childCount; i++) { View childView = getChildAt(i); //对当前获取的子 View 进行测量 measureChild(childView, widthMeasureSpec, heightMeasureSpec); //按比例计算子 View 的高度 int childViewHeight = childView.getMeasuredHeight() * columnWidth / childView.getMeasuredWidth(); //获取最小高度的列 int minHeightColumn = getMinHeightColumn(); //获取子 View 的 LayoutParams,并强转为 WaterfallLayoutParams,记录子 View 的左上右下四个边沿 WaterfallLayoutParams layoutParams = (WaterfallLayoutParams) childView.getLayoutParams(); layoutParams.left = minHeightColumn * (columnWidth + mHorizontalSpace); layoutParams.top = columnHeight[minHeightColumn]; layoutParams.right = layoutParams.left + columnWidth; layoutParams.bottom = layoutParams.top + childViewHeight; //添加图片后把高度加进去 columnHeight[minHeightColumn] = layoutParams.bottom + mVerticalSpace; } //测量高度为最高度的列的高度 measuredHeight = columnHeight[getMaxHeightColumn()]; //测量的最终目的 setMeasuredDimension setMeasuredDimension(iWidthSpecMode == MeasureSpec.EXACTLY ? iWidthSpecSize : measuredWith, iHeightSpecMode == MeasureSpec.EXACTLY ? iHeightSpecSize : measuredHeight); }
四、onLayout()
这样 onLayout() 方法就变得简洁了很多。
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = this.getChildAt(i); WaterfallLayoutParams lParams = (WaterfallLayoutParams)child.getLayoutParams(); child.layout(lParams.left, lParams.top, lParams.right, lParams.bottom); } //由于程序会多次调用测量布局,所以布局完清空数据 //不清空数据,同一个 View 会被多次引用布局,以最后一次布局为主, //可能导致所有子 View 的布局都在 FlowLayout 高度之外,导致界面没有东西 clearTop(); }
五、监听
监听还是一样,没有改变
//监听类接口 public interface OnItemClickListener{ void onItemClick (View v, int index); } //监听类的实现 public void setOnItemClickListener(final OnItemClickListener listener){ int childCount = getChildCount(); for(int i = 0 ; i < childCount ; i++){ View childView = getChildAt(i); final int finalI = i; childView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listener.onItemClick(v, finalI); } }); } }
六、三个业务方法
//获取当前高度最小的列 private int getMinHeightColumn() { int minHeightColumn = 0; for (int i=0; i<columnCount; i++) { if (columnHeight[i] < columnHeight[minHeightColumn]) { minHeightColumn = i; } } return minHeightColumn; } //获取当前高度最大的列 private int getMaxHeightColumn() { int minHeightColumn = 0; for (int i=0; i<columnCount; i++) { if (columnHeight[i] > columnHeight[minHeightColumn]) { minHeightColumn = i; } } return minHeightColumn; } //初始化没列高度 private void clearTop() { for (int i=0; i<columnCount; i++) { columnHeight[i] = 0; } }
七、附
代码链接:http://download.csdn.net/detail/qq_18983205/9849283
这里引用 v7 包,报错的可以参考 http://blog.csdn.net/qq_18983205/article/details/60874618
阅读全文
0 0
- (四)UI绘制流程-瀑布流布局
- 瀑布流布局的实现(一)
- (iOS)简单的瀑布流布局
- 瀑布流布局浅析
- 瀑布流布局
- 瀑布流布局浅析
- 瀑布流布局浅析
- 瀑布流布局浅析
- js瀑布流布局
- 瀑布流布局浅析
- 瀑布流布局浅析
- 瀑布流布局浅析
- 瀑布流布局浅析
- 瀑布流布局浅析
- 图片瀑布流布局
- Android 瀑布流布局
- 瀑布流布局代码
- 瀑布流布局
- 06.java数据类型详解
- 为什么实体类需要实现序列化
- 流量、电量、弱网环境测试
- popupwindow工具类
- JavaScript、Ajax与jQuery的关系
- (四)UI绘制流程-瀑布流布局
- c随机函数
- 在Modelsim仿真时出现的dirctory未找到或者出现error:in read mode
- 创建maven项目
- JVM类加载机制
- GDI
- 使用TCP/IP协议实现客户端和服务端全双工通信(转载)
- 使用PHP代码实现迪杰特斯拉算法
- FATE(HDU-2159)