接上篇《android开发艺术探索》读书笔记(三)

No1:

View的三大流程:测量流程、布局流程、绘制流程

No2:

ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成的。

在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联。

No3:

View的绘制流程是从ViewRoot的performTraversals方法开始的,它经过measure、layout和draw三个过程才能最终将一个View绘制出来,measure用来测量View的宽和高,layout用来确定View在父容器中的放置位置(View的最终宽/高和四个顶点的位置),draw负责View绘制在屏幕上。

No4:

DecorView其实是一个FrameLayout,View层的事件都先经过DecorView,然后才传递给我们的View。

No5:

performTraversals会依次调用performMeasure、performLayout、performDraw三个方法,这三个方法分别完成顶级View的measure、layout和draw这三个流程。

其中performMeasure会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有的子元素进行measure过程,这个时候measure流程就从父容器传递到子元素中了,这样就完成了依次measure过程。接着子元素会重复父容器的measure过程,如此反复就完成了整个View树的遍历。

No6:

子元素的MeasureSpec的创建与父容器的MeasureSpec和子元素本身的LayoutParams有关,此外还和View的margin及padding有关。

getChildMeasureSpce的主要作用是根据父容器的MeasureSpec同时结合View本身的LayoutParams来确定子元素的MeasureSpec,参数中的padding是指父容器中已占用的空间大小,因此子元素可用的大小为父容器的尺寸减去padding

No7:

measure的两种情况:

1.如果只是一个原始的View,那么通过measure方法就完成了其测量过程

2.如果是一个ViewGroup,除了完成自己的测量过程外,还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个流程。

No8:

View的measure方法是一个final类型的方法,这意味着子类不能重写此方法。

No9:

measureChild的思想就是取出子元素的LayoutParams,然后再通过getChildMeasureSpec来创建子元素的MeasureSpec,接着将MeasureSpec直接传递给View的measure方法来进行测量。

No10:

如何解决onCreate、onStart、onResume中无法得到某个View的宽、高信息?

1.Activity、View的onWindowFocusChanged:View已经初始化完毕了,宽高已经准备好了

public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
if(hasFocus){
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
}
}

2.view.post(runnable):通过post可以将runnable投递到消息队列的尾部,然后等待Looper调用此runnable的时候,View也已经初始化好了

protected void onStart(){
super.onStart();
view.post(new Runnable(){
@Override
public void run(){
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
}
});
}

3.ViewTreeObserver--当View树的状态发生改变或者View树内部的View的可见性发生改变时,onGlobalLayou方法将被回调,因此这是获取View的宽高一个很好的时机

protected void onStart(){
super.onStart();
ViewTreeObserver observer = view.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout(){
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int width = view.getMeasureWidth();
int height = view.getMeasureHeight();
}
});
}

4.view.measure(int widthMeasureSpec,int heightMeasureSpec)

根据View的LayoutParams来分情况处理

match_parent直接放弃

具体的数值(px)

int widthMeasureSpec = MeasureSpec.makeMeasureSpec(100,MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(100,MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec,heightMeasureSpec);

wrap_content

int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1<<30)-1,MeasureSpec.AT_MOST);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1<<30)-1,MeasureSpec.AT_MOST);
view.measure(widthMeasureSpec,heightMeasureSpec);

No11:

layout方法大致流程:首先通过setFrame方法来设定View的四个顶点的位置,即初始化mLeft、mRight、mTop和mBottom这四个值,View的四个顶点一旦确定,那么View在父容器中的位置也就确定了;接着会调用onLayout方法,这个方法的用途是父容器确定子元素的位置。

No12:

View的测量宽/高和最终宽/高有什么区别(View的getMeasuredWidth/getMeasuredHeitght和getWidth/getHeight)

在View的默认实现中,View的测量宽/高和最终宽/高是相等的,只不过测量宽/高形成于View的measure过程,而最终宽/高形成于View的layout过程,即两者的赋值时机不同,测量宽/高的赋值时机稍微早一些。

如果重写View的layout方法,才会导致View的最终宽/高和测量宽/高不一致

No13:

View的绘制过程步骤:

1.绘制背景background.draw(canvas)

2.绘制自己onDraw

3.绘制children(dispatchDraw)

4.绘制装饰(onDrawScrollBars)

No14:

View绘制过程的传递是通过diapatchDraw来实现的,dispatchDraw会遍历调用所有子元素的draw方法,如此draw事件就一层层地传递了下去。

No15:

自定义View

1.继承View重写onDraw方法:主要用于实现一些不规则的效果

2.继承ViewGroup派生特殊的Layout:主要用于实现自定义的布局

3.继承特定的View(比如TextView):用于扩展某种已有的View的功能

4.继承特定的ViewGroup(比如LinearLayout):效果看起来像几种View组合在一起的时候

No16:

自定义View须知:

1.让View支持warp_content--对于直接继承自View的控件,如果不对wrap_content做特殊处理,那么使用wrap_content就相当于使用match_parent

2.如果有必要,让你的View支持padding--因为padding默认不生效

3.尽量不要在View中使用Handler,没必要--因为View内部本身就提供了post方法

4.View中如果有线程或者动画,需要及时停止,参考View#onDetchedFromWindow--防止内存泄露

5.View带有滑动嵌套情形时,需要处理好滑动冲突

No17:

自定义属性:请看我的另一篇自定义属性

No18:

MeasureSpec代表一个32位int值,高2位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,而SpecSize是指在某种测量模式下的规格大小。

系统内部是通过MeasureSpec来进行View的测量,但是正常情况下我们使用View指定MeasureSpec,尽管如此,但是我们可以给View设置LayoutParams。在View测量的时候,系统会将LayoutParams在父容器的约束下转换成对应的MeasureSpec,然后再根据这个MeasureSpec来确定View测量猴的宽/高。

《android开发艺术探索》读书笔记(四)--View工作原理的更多相关文章

  1. android开发艺术探索读书笔记之-------view的事件分发机制

    View的点击事件的分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生后,系统需要把这个事件传递给一个具体的View,而这个过程就是分发过程. 分发过程主要由以下 ...

  2. Android开发艺术探索读书笔记——01 Activity的生命周期

    http://www.cnblogs.com/csonezp/p/5121142.html 新买了一本书,<Android开发艺术探索>.这本书算是一本进阶书籍,适合有一定安卓开发基础,做 ...

  3. Android开发艺术探索读书笔记——进程间通信

    1. 多进程使用场景 1) 应用某些模块由于特殊需求须要执行在单独进程中. 如消息推送,使消息推送进程与应用进程能单独存活,消息推送进程不会由于应用程序进程crash而受影响. 2) 为加大一个应用可 ...

  4. Android开发艺术探索学习笔记(四)

    第四章 View的工作原理 4.1初识ViewRoot和DecorView ViewRoot是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成 ...

  5. Android开发艺术探索学习笔记(三)

    第三章  View的事件体系 3.1 View基础知识 3.1.1 什么是view View 是Android中所有控件的基类,是一种界面层的控件的一种抽象,它代表了一个控件. 3.1.2 View的 ...

  6. Android开发艺术探索(三)——View的事件体系

    一.View基础知识 主要介绍内容有:View的位置参数.MotionEvent和TouchSlope对象.VelocityTracker.GestureDetector和Scroller对象 1.什 ...

  7. Android开发艺术探索学习笔记(六)

    第六章 Android的Drawable  Drawable的优点:使用简单,比自定义view的成本要低:非图片类型的Drawable占用空间小,有利于减小APK安装包的大小. 6.1Drawable ...

  8. Android开发艺术探索学习笔记(十一)

    第十一章  Android的线程和线程池 从用途上来说,线程分为子线程和主线程,主线程主要处理和界面相关的事情,而子线程往往用于执行耗时的操作.AsyncTask,IntentService,Hand ...

  9. Android开发艺术探索学习笔记(一)

    第一章 Activity的生命周期和启动模式 1.1Activity的生命周期全面解析 1.1.1典型情况下的生命周期分析 (1)在两个Activity进行切换时,当前的Activity的onPaus ...

  10. Android开发艺术探索学习笔记(十)

    第十章  Android的消息机制 面试中经常会被问到的一个问题:handler是如何在子线程和主线程中进行消息的传递的,这个问题通过了解Android的消息机制可以得到一个准确的答案. Androi ...

随机推荐

  1. python3 第三章 - 程序的基本结构

    1.编码 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串. 当然你也可以为源码文件指定不同的编码: # -*- coding: cp-1252 -* ...

  2. JavaScript ES6 Arrow Functions(箭头函数)

    1. 介绍 第一眼看到ES6新增加的 arrow function 时,感觉非常像 lambda 表达式. 那么arrow function是干什么的呢?可以看作为匿名函数的简写方式. 如: var ...

  3. SQLSERVER存储过程语法详解

    CREATE PROC [ EDURE ] procedure_name [ ; number ] [ { @parameter data_type } [ VARYING ] [ = default ...

  4. Linux 中su和sudo命令的几个注意点

    1 su与su - 的区别 1.1命令说明 su对应是是no-login shell的方式进行账号登陆,命令行的变量配置还是切换账号前的变量. su-对应的是login shell的方式进行账号登陆, ...

  5. Servlet--取得初始化配置信息

    关于这块内容,主要就是玩一个接口:ServletConfig.先翻下API,了解一下. 定义: public interface ServletConfig 这个接口定义了一个对象,通过这个对象,Se ...

  6. j2e应用相关技术

    j2e应用相关技术 轻量级j2e应用以传统的jsp作为变现层技术,以一系列开源框架作为MVC层,中间件,持久层解决方案,并将这些开源框架有机组合在一起,使得j2e具有高度的可扩展性,可维护性. ser ...

  7. Oracle Start With关键字

    Oracle Start With关键字 前言 旨在记录一些Oracle使用中遇到的各种各样的问题. 同时希望能帮到和我遇到同样问题的人. Start With (树查询) 问题描述: 在数据库中, ...

  8. android CheckBox与监听

    <CheckBox  android:id="@+id/cb1"  android:layout_width="fill_parent"  android ...

  9. git常用命令,学git代码管理

    下面是我整理的常用 Git 命令清单.几个专用名词的译名如下. Workspace:工作区 Index / Stage:暂存区 Repository:仓库区(或本地仓库) Remote:远程仓库 一. ...

  10. 隐藏C语言黑窗口

    隐藏C语言程序运行的黑窗口,加入预编译命令: (预编译,Linker链接,windows模式,黑窗口是dos模式) #pragma comment(linker,"/subsystem:\& ...