(三)UI绘制流程-流式布局
来源:互联网 发布:java api1.6文档下载 编辑:程序博客网 时间:2024/06/15 07:41
版权声明:本文为博主原创文章,未经博主允许不得转载。
本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。
一.前言
前两篇对源码进行了一些分析,内容较多,在这边再稍微讲一下。
1.View 与 ViewGroup
ViewGroup 虽然继承于 View,但却是一个抽象类,我们通常把容器按 View 和 ViewGroup 来进行区分。ViewGroup 类似于 View 的数组,里面存放多个 View,比如 LayoutParams、RelativeLayout 等。ViewGroup 会传递给 View 建议 的测量规格(包括模式和大小),View 会根据 ViewGroup 传递的测量规格,结合自身的设置进行实际大小的测量。
二、LayoutParams
ViewGroup 需要指定一个 LayoutParams 来确定里面的 View 支持哪些属性在。 LinearLayout 中添加 View 的时候,可以写 layout_gravity,layout_weight 属性;RelativeLayout 中的 View 有layout_centerInParent 属性,却没有 layout_gravity,layout_weight。这些 View 支持的属性可以通过重写 ViewGroup 的 generateLayoutParams()方法来进行设置。
二、分析
1.generateLayoutParams()没有特殊要求,我们直接用 MarginLayoutParams(getContext(),attrs)。
2.onMeasure() 测量自身宽高的同时把每一行存放的 View 和行高进行保存,(在 onLayout()中也要用到每一行的元素,避免再次循环判断)
3.onLayout()把每行 View 进行摆放。
三、实现
1.每一行的封装类
//每一行的封装类 protected class LineView { //每一行的子View private List<View> mViewLine; //行高 private int lineHeight; public LineView() { mViewLine = new ArrayList<View>(); lineHeight = 0; } public List<View> getmViewLine() { return mViewLine; } public void setmViewLine(List<View> mViewLine) { this.mViewLine = mViewLine; } public int getLineHeight() { return lineHeight; } public void setLineHeight(int lineHeight) { this.lineHeight = lineHeight; } }
二、generateLayoutParams()
@Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(),attrs); }
三、onMeasure()
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //获取父容器为 FlowLayout 设置的测量模式和大小的建议值 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; //记录当前行的宽高 int iCurLineW = 0; int iCurLineH = 0; int childCount = getChildCount(); //记录当前子 View 的宽高 int iChildWith = 0; int iChildHeight = 0; //存储每行 View LineView lineView = new LineView(); //循环遍历子 View,进行子 View 的测量已经 FlowLayout 宽高的计算 for (int i=0; i<childCount; i ++) { View childView = getChildAt(i); //对当前获取的子 View 进行测量 measureChild(childView, widthMeasureSpec, heightMeasureSpec); //获取子 View 的 MarginLayoutParams,并计算出子 View 所要占用的宽高 MarginLayoutParams childLayoutParams = (MarginLayoutParams) childView.getLayoutParams(); iChildWith = childView.getMeasuredWidth() + childLayoutParams.leftMargin + childLayoutParams.rightMargin; iChildHeight = childView.getMeasuredHeight() +childLayoutParams.topMargin + childLayoutParams.bottomMargin; //当前行放不下子 View, 换行 if (iChildWith + iCurLineW > iWidthSpecSize) { //测量高度叠加,测量宽度取最大值 measuredHeight += iCurLineH; measuredWith = Math.max(measuredWith, iCurLineW); //记录当前行高度,并保存到 lineViewList lineView.setLineHeight(iCurLineH); lineViewList.add(lineView); //重新对当前行宽高进行赋值 iCurLineW = iChildWith; iCurLineH = iChildHeight; //新建一行,添加子 View lineView = new LineView(); lineView.getmViewLine().add(childView); } else { //当前行放的下子 View, 记录信息 //添加子 View lineView.getmViewLine().add(childView); //当前行宽度叠加,当前行高度取最大值 iCurLineW += iChildWith; iCurLineH = Math.max(iChildHeight, iCurLineH); } } //添加最后一行数据 //测量高度叠加,测量宽度取最大值 measuredHeight += iCurLineH; measuredWith = Math.max(measuredWith, iCurLineW); //记录当前行高度 lineView.setLineHeight(iChildHeight); lineViewList.add(lineView); //测量的最终目的 setMeasuredDimension setMeasuredDimension(iWidthSpecMode == MeasureSpec.EXACTLY ? iWidthSpecSize : measuredWith, iHeightSpecMode == MeasureSpec.EXACTLY ? iHeightSpecSize : measuredHeight); }
四、onLayout()
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //记录当前子 View 的四个边沿 int left,top,right,bottom; //记录当前子 View 包括 Margin 的左边沿和上边沿 int curTop = 0; int curLeft = 0; //每一行数据 LineView lineView; //遍历每一行数据 for (int i=0; i<lineViewList.size(); i++) { //获取当前行的数据 lineView = lineViewList.get(i); //遍历当前行所有 View for (int j=0; j<lineView.getmViewLine().size(); j++) { //获取当前子 View View childView = lineView.getmViewLine().get(j); //获取子 View 的 MarginLayoutParams,并计算出子 View 的四个边沿 MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams(); left = curLeft + layoutParams.leftMargin; top = curTop + layoutParams.topMargin; right = left + childView.getMeasuredWidth(); bottom = top + childView.getMeasuredHeight(); //布局子 View childView.layout(left, top, right, bottom); //计算下一个子 View 的左边沿 curLeft = right + layoutParams.rightMargin; } //换行,重置子 View 包括 Margin 的左边沿和上边沿 curLeft = 0; curTop += lineView.getLineHeight(); } //由于程序会多次调用测量布局,所以布局完清空数据 //不清空数据,同一个 View 会被多次引用布局,以最后一次布局为主, //可能导致所有子 View 的布局都在 FlowLayout 高度之外,导致界面没有东西 lineViewList.clear(); }
五、监听
//监听类接口 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); } }); } }
六、附
代码链接:http://download.csdn.net/detail/qq_18983205/9848440
这里引用 v7 包,报错的可以参考 http://blog.csdn.net/qq_18983205/article/details/60874618
- (三)UI绘制流程-流式布局
- (一)UI绘制流程-源码分析
- Android UI绘制流程
- view的流程(测量,布局,绘制)
- (二)UI绘制流程-绘制过程源码分析
- Android——UI(一):UI绘制流程
- Android view的绘制流程(三)
- Android UI的绘制流程
- Android UI绘制流程(一)
- Android UI绘制流程(二)
- FrameLayout布局绘制流程解析
- android 布局绘制流程解析
- UI绘制流程分析(源码级分析)
- (四)UI绘制流程-瀑布流布局
- Android源码解析(十八)-->Activity布局绘制流程
- Android UI测量、布局、绘制过程探究
- iOS UI绘制和布局基础解析
- 源码分析android的UI绘制流程
- 用opensmile批量提取语音特征
- hadoop-hdfs-架构
- Linux下的共享内存
- python leetcode相关题目
- OpenGL 矩阵 行序 列序
- (三)UI绘制流程-流式布局
- 2011蓝桥杯 最小公倍数 NOYJ517
- Java定时任务调度工具-Timer
- 实现手机左右滑屏效果
- 2017暑期实习面经分享(大数据&Java&后台)
- c++---回文数
- Tornado——一个异步web服务器
- Java首选项Preferences
- 分割字符串