Android View绘制13问13答
2016-02-04 16:06
507 查看
1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view?
答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。
2.view的测量宽高和实际宽高有区别吗?
答:基本上百分之99的情况下都是可以认为没有区别的。有两种情况,有区别。第一种 就是有的时候会因为某些原因 view会多次测量,那第一次测量的宽高 肯定和最后实际的宽高 是不一定相等的,但是在这种情况下
最后一次测量的宽高和实际宽高是一致的。此外,实际宽高是在layout流程里确定的,我们可以在layout流程里 将实际宽高写死 写成硬编码,这样测量的宽高和实际宽高就肯定不一样了,虽然这么做没有意义 而且也不好。
3.view的measureSpec 由谁决定?顶级view呢?
答:由view自己的layoutparams和父容器 一起决定自己的measureSpec。一旦确定了spec,onMeasure中就可以确定view的宽高了。
顶级view就稍微特殊一点,对于decorView的测量在ViewRootImpl的源码里。
View Code
答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。
2.view的测量宽高和实际宽高有区别吗?
答:基本上百分之99的情况下都是可以认为没有区别的。有两种情况,有区别。第一种 就是有的时候会因为某些原因 view会多次测量,那第一次测量的宽高 肯定和最后实际的宽高 是不一定相等的,但是在这种情况下
最后一次测量的宽高和实际宽高是一致的。此外,实际宽高是在layout流程里确定的,我们可以在layout流程里 将实际宽高写死 写成硬编码,这样测量的宽高和实际宽高就肯定不一样了,虽然这么做没有意义 而且也不好。
3.view的measureSpec 由谁决定?顶级view呢?
答:由view自己的layoutparams和父容器 一起决定自己的measureSpec。一旦确定了spec,onMeasure中就可以确定view的宽高了。
顶级view就稍微特殊一点,对于decorView的测量在ViewRootImpl的源码里。
package com.example.administrator.motioneventtest; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; /** * Created by Administrator on 2016/2/4. */ //这里我们只处理了padding的状态 没有处理margin的状态,子view的margin 对measure和layout的影响 //就留给读者自己完成了 public class CustomHorizontalLayout extends ViewGroup { //设置默认的控件最小是多少 这里不提供自定义属性了 写死在代码里 你们可以自行拓展 final int minHeight = 0; final int minWidth = 0; public CustomHorizontalLayout(Context context) { super(context); } public CustomHorizontalLayout(Context context, AttributeSet attrs) { super(context, attrs); } public CustomHorizontalLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measureWidth = 0; int measureHeight = 0; final int childCount = getChildCount(); measureChildren(widthMeasureSpec, heightMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); final View childView = getChildAt(0); final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int paddingTop = getPaddingTop(); final int paddingBottom = getPaddingBottom(); //没有子控件 时 我们的宽高要作特殊处理 if (childCount == 0) { //当没有子控件时,如果长宽有一个为wrap 那么就让这个控件以最小的形式展现 //这里我们最小设置为0 if (widthSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(minWidth, minHeight); } else { //否则根据我们的layout属性来 setMeasuredDimension(getLayoutParams().width, getLayoutParams().height); } } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { measureWidth = childView.getMeasuredWidth() * childCount; measureHeight = childView.getMeasuredHeight(); setMeasuredDimension(paddingLeft + measureWidth + paddingRight, paddingTop + measureHeight + paddingBottom); } else if (heightSpecMode == MeasureSpec.AT_MOST) { measureHeight = childView.getMeasuredHeight(); setMeasuredDimension(paddingLeft + paddingRight + widthSpecSize, paddingTop + paddingBottom + measureHeight); } else if (widthSpecMode == MeasureSpec.AT_MOST) { measureWidth = childView.getMeasuredWidth() * childCount; setMeasuredDimension(paddingLeft + paddingRight + measureWidth, paddingTop + paddingBottom + heightSpecSize); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int paddingTop = getPaddingTop(); final int paddingBottom = getPaddingBottom(); //左边初始位置为0 int childLeft = 0 + paddingLeft; final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View childView = getChildAt(i); if (childView.getVisibility() != View.GONE) { final int childWidth = childView.getMeasuredWidth(); childView.layout(childLeft, 0 + paddingTop, childLeft + childWidth, paddingTop + childView.getMeasuredHeight()); childLeft += childWidth; } } } }
View Code
相关文章推荐
- Android 第八天(下午)
- 【Android】3.20 示例20—全景图完整示例
- android JNI基本库(jsting转string和C多线程调用java方法的说明)
- Android自动补全
- Android开发学习路线
- ionic平台下的版本升级
- Android Studio Gradle
- Android-Universal-Image-Loader三大组件DisplayImageOptions、ImageLoader、ImageLoaderConfiguration详解
- android launcherMode 的学习
- android string.xml中的占位符
- android之用scrollview实现控件滑动固定效果
- android自定义环形对比图(外环有类似进度条的旋转动画)
- 【Android】3.19 示例19--全景图HelloWorld
- Android RecycleView(四)——时间轴
- Android 设置进度条背景
- 【Android】3.18 示例18--自定义绘制功能
- Android.util下实用工具类
- android关于实现去掉标题栏的几种方法
- android - 跳转拨打电话、通讯录、直接拨打电话
- 【Android】3.17 示例17--周边雷达功能