Android(安卓)知识点总结 (二) view绘制流程
相关文章:
Android 知识点总结(目录) https://blog.csdn.net/a136447572/article/details/81027701
view绘制主要包括三个方面:
measure 测量组件本身的大小
layout 确定组件在视图中的位置
draw 根据位置和大小,将组件画出来
measure
绘制组件的大小
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
重写onMeasure 是 会有两个参数 widthMeasureSpec与heightMeasureSpec 这连个参数是系统提供的控件高度的建议值但最终值需要通过setMeasuredDimension() 方法来设置
int widthMeasure = MeasureSpec.getSize(widthMeasureSpec); int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec); int heightMeasure = MeasureSpec.getSize(heightMeasureSpec); int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
widthMeasureSpec与heightMeasureSpec 值 都是一个组合尺寸,它是一个32位bit值,高两位是尺寸模式specMode,低30位是尺寸大小值
可以通过 MeasureSpec.getSize() 与 MeasureSpec.getMode()方法分别获取尺寸模式和具体值
MeasureSpec.EXACTLY 用户指定 match_parent 或大小 :layout_width="50dip"MeasureSpec.AT_MOST 用户指定 android:layout_width="wrap_content"MeasureSpec.UNSPECIFIED 是用户未指定尺寸,这种情况不多
在 ViewGroup中 需要通过 measureChildren(widthMeasureSpec,heightMeasureSpec); 来计算ViewGroup中所有子View 的大小 然后通过 getChildCount()获取数量并循环计算总宽高
measureChildren(widthMeasureSpec,heightMeasureSpec); int count = getChildCount(); for (int i = 0; i < count ; i++) { View child = getChildAt(i); //计算过程 if ( (childWidth + lineWidth) > widthMeasure ){ width = Math.max(lineWidth,childWidth); height += lineHeight; lineHeight = childHeight; lineWidth = childWidth; }else{ lineWidth +=childWidth ; lineHeight = Math.max(lineHeight,childHeight); } if (i == count -1 ){ height += lineHeight ; width = Math.max(width,lineWidth); }}
最后得到计算出来的值 通过 setMeasuredDimension
方法设置宽高值
setMeasuredDimension((widthMeasureMode == MeasureSpec.EXACTLY) ?widthMeasure:width,(heightMeasureMode==MeasureSpec.EXACTLY) ?heightMeasure:height);
在计算中如果用户指定margin值时 则需要我们单独计算并添加,需要重写generateLayoutParams
来获得准确的margin ,可以直接返回 new MarginLayoutParams(getContext(), attrs);
@Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); }
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
onLayout
确定组件在视图中的位置 如果自定义时 是必须重写的方法
@Override protected void onLayout(boolean b, int i, int i1, int i2, int i3) { }
在onLayout 中 与onMeasure 相同,需要通过 int count = getChildCount();
获取子View 数量 并通过循环设置每个view的layout
代码是其他自定义view的代码
@Override protected void onLayout(boolean b, int i, int i1, int i2, int i3) { int count = getChildCount(); int lineWidth = 0; int lineHeight = 0; int top = 0; int left = 0; for (int j = 0; j < count; j++) { View child = getChildAt(j); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; if ((childWidth + lineWidth) > getMeasuredHeight()) { top += lineHeight; left = 0; lineHeight = childHeight; lineWidth = childWidth; } else { lineHeight = Math.max(lineHeight, childHeight); lineWidth += childWidth; } int lc = left + lp.leftMargin; int tc = top + lp.topMargin; int rc = lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); child.layout(lc, tc, rc, bc); left += childHeight; } }
draw
根据位置和大小,将组件画出来
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); int originY = 300; int halfWaveLen = mItemWaveLength/2; mPath.moveTo(-mItemWaveLength+dx,originY+dy); for (int i = -mItemWaveLength;i<=getWidth()+mItemWaveLength;i+=mItemWaveLength){ mPath.rQuadTo(halfWaveLen/2,-50,halfWaveLen,0); mPath.rQuadTo(halfWaveLen/2,50,halfWaveLen,0); } mPath.lineTo(getWidth(),getHeight()); mPath.lineTo(0,getHeight()); mPath.close(); canvas.drawPath(mPath,mPaint); canvas.drawPath(path,mPaint1); }
onDraw 中 主要是通过在canvas上进行绘制连显示图片
view 在绘制的时候会通过上面这三个方法来确定view 的大小,位置,和其中的内容 ,最终显示到界面上
更多相关文章
- Android(安卓)4.4.4 锁屏界面时间大小修改
- Android(安卓)使用Camera 打开预览Demo
- Dev Guide_Android(安卓)Basics_Application Fundamentals
- Android(安卓)组件化开发ButterKnife配置和相关问题
- Android(安卓)获取系统或SDCARD剩余空间信息
- Lifecycle-Aware Components生命周期组件 Lifecycle、LiveData
- 简单明了 的java、android线程池
- 再也不信网上流传的方法了!!android创建组件的真正写法!
- Android中使用NavigationView实现抽屉侧滑效果中Menu菜单栏设置