说到绘制,其实就是如何把一个view的对象,变成手机上可视的图形。很多人总结3个过程:测量,布局,绘制。这也是所有的要显示图形的程序所应该抽象的3个步骤,测量就是测量出你view的大小,布局就是要显示在屏幕的哪个坐标位置,绘制就是把图形画到屏幕上。view和viewgroup的处理方法是不同的。

view:

1.measure:要测量应该考虑的就是view的大小,重点看view中的measure,首先是判断是否有必要测量view中有一个mprivateflags是一个标志位,标志了view的所有的状态表示。判断是否要FROCE_LAYOUT。然后判断现在的测量的大小和一个之前测量的大小是否一样。之前的测绘mOldWidthMeasurSpec和mOldHighMeasurSpec存储。初始值为Integer.MINVALUE.

tip:谈到标志的存储,这里有很大的学问,要知道并不是所有的标志都是boolean存储。还可以使用int,而且int要保存的标志位和他的位数是一致的,也就是int有32位,他就可以表示32个标志。怎么做到?在java中位的操作就是用| & 和&~。当我们增加一个标志位的时候使用|,判断一个标志使用&,消除一个标志使用&~。int的每一个bit都可以表示一个标志位,首先你要定义各种标志位使用0x0100 0000这样,然后假如有一个状态值为0x0100 0000 和默认值一样&之后就是非0的值,在java中Boolean必须使用 == 来判断,所以mPrivateFlags & FORCE_LAYOUT就是判断是否含有这个标志位。当你要添加一个标志位的使用就要使用| 。删除使用&~。这样的操作在android flag中比比皆是。这样做的好处是什么?不用定义多个标志位。仅仅使用一个int值就可以了。另外还相对于boolean减少了空间。(关于boolean占用多少个字节来说,有人说1byte,有人说1bit。虚拟机实现不同,也有一定关系。但是大量的标志位的时候还是使用int的这种位操作更加靠谱)

mOldHighMeasurSpec为什么将这两个旧的宽高设置为0?含义仅仅是0?判断完,当需要测量的时候,就调用了  onMeasure(widthMeasureSpec, heightMeasureSpec);细心一点就会想为什么不使用mWidth这样容易记的东西?而是使用冗长的名称?onmeasure方法里面就使用了一个setMeasuredDimension来设置宽高,在view中实际使用mMeasuredWidth和mMeasuredHeight来表示view的宽高。所以即使是我们继承了view也要使用setMeasuredDimension来设置测量好的宽高。带着所有的疑问,让我们重点关注一个view的内部静态类MeasureSpec。

MeasureSpec:

这是一个测量中的最关键的类,他把一个int表示了两个概念:模式,大小。模式这里面定义了3种模式:UNSPECIFIED,EXACTLY,AT_MOST用来分别表示未知,已测量,最大可用。大小就是测量的大小。当你传递进来一个数值的时候这个时候包含了两种信息:如果是未知,就需要你亲自测量。如果是已知,就使用测量好的,如果是最大可用,就用可使用最大值。

叙述完概念之后,看一下实际的数值UNSPECIFIED是0x0000 0000,EXACTLY是0x1000 0000,AT_MOST是0x2000 0000.知道为什么我这么写出来吗?对又是标志位的使用,这里为什么可以把int表示为mode和size两种概念,就是前两位表示模式,后30为表示大小。这里面还定义了两个辅助的常量就是MODE_SHIFT是30也就是说后30位表示大小,MODE_MASK表示“面具”就是说0x3000 0000为什么说是面具?其实是英语含义,我这么叫他是因为他可以除去模式只留下大小信息。

模式:首先来说如何获取一个模式?measureSpec & MODE_MASK,之前就说过使用&来判断有无标志位。大小:获取大小的方法一样measureSpec & ~MODE_MASK消除了标志位就是大小信息。那么怎么生成一个这样的measureSpec ?mode+size就可以了。

这样应该理解了MeasureSpec,在onmeasure里面有一个getDefaultSize的方法,这个方法就是默认的处理测量的,在UNSPECIFIED的时候使用传递来的值,在EXACTLY的时候使用测绘值,最大可用也是默认值(也就是measureSpec附带的size大小)。那传递值是?getSuggestedMinimumWidth这个里面有,也就是说默认我不测绘的时候会有一个默认的宽高。就是背景大小和mMinWidth比较。背景实际是一个bitmap也就是看一下这个背景的大小。然后和xml中的mMinwidth设置的值做一个比较。最小的就是默认值。也正是AT_MOST的含义,求出最大的可用宽高。

tip:那么什么时候会传递EXACTLY?什么时候传递AT_MOST,下面的仅仅是rootview的策略!就是decroview

case ViewGroup.LayoutParams.MATCH_PARENT:
          // Window can't resize. Force root view to be windowSize.
          measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
          break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
          // Window can resize. Set max size for root view.
          measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
          break;

default:
    // Window wants to be an exact size. Force root view to be that size.
    measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
    break;
也就是说既然view必须设置LayoutParams。这里就是他的用途,当你是一个填充窗体的时候,那么你的view所占据的大小就是确定的并且是父viewgroup大小windowSize(因为只有在viewgroup中才会有view)。在包裹内容的时候,view的大小就是可用的最大大小也是windowsize。这里面就是说无论是什么都要给rootview一个windowsize,真正的布局划分和测量在viewgroup中!

到处为止measure就算完了。有点乱。其实就是measure回调onMeasure,其实最关键的并不在这里,而在viewgroup中。

2layout:这个是布局,布局就是把位置表示出来,注意的是这里的位置view中的mLeft等变量表示的,但是却不是屏幕上的绝对位置,是基于父类的位置,这个概念很重要。关系到了layout的使用首先setFrame来看一下是否是布局变动了,如果变动了就设置到变量中,这里的onlayout就比较鸡肋了,仅仅是提供了一个回调。我们要改变布局的时候可以直接使用layout,而不用等待onlayout的回调,其实主要是setframe,但是这个是受保护的,我们不可以随便使用。

tip: 关于这个layout最关键的其实是我们如何使得view进行移动的一个方法,这里还有一个方法叫做scrollto和scrollby.这些概念都是基于view怎么布局的问题,一个view要想布局就要知道父布局,然后进行偏移,这个偏移是mScrollX和mScrollY通过scrollTo来移动的,表示把view移动到基于当前view的x和y处(坐标原点在view左上角),然后这个x,y就被设置为了mScrollX和mScrollY。scrollby是调用了scrollTo(mScrollX + x, mScrollY + y);也就是说是基于当前的位置再移动x,y。

了解了这个概念之后你就可以自定义移动view了不要以为移动只可以用scrollTo,还有就是layout也可以,但是layout实际上移动的是view在viewgroup中的位置,而scrollTo是移动的view在view本身的布局的位置。影响view在屏幕中的绝对位置的有3个:mLeft,mScrollX,paddingLeft也就是说mLeft是layout控制,mScrollX是由ScrollTo控制。主要就是利用这两个东西来控制view。所以一个view只能在父布局中移动。但是你要明白的是你的界面控制是你来控制的,所有移动都可以实现。只是布局设计的问题。

3draw:绘制,首先是绘制背景mBGDrawable,确定背景大小,然后执行canvas.translate(scrollX, scrollY);background.draw(canvas);canvas.translate(-scrollX, -scrollY);好好想一下这一个,你就会体会出view是无穷去界的,而我们的眼睛限制了我们。你要知道的所有的东西都在画布canvas上,这个是进行了画布的移动。画上了背景在把画布移动回去。也就是说canves是无穷无界的。最后执行dispatchdraw其实就是画view的各个控件。这个方法在子类中扩展

viewgroup:

1。measureChildren:里面调用measureChild。首先还是检验模式,当为确定或者是最大值得时,无论包裹内容还是占据父窗体都是传递来的大小。当无法确定的时候,使用的是0.实际上在继承了viewgroup之后,你可以复写onmeasure方法,进行自定义的测量。

2.layout,这个viewgroup本身就没有实现,由于是交给子类实现的,所以根本就设为空方法。

3.draw viewgroup管理的是view的布局和大小,本身是没有太多的绘制,也没有实现父类。都交给了子类。

关于绘制view,更加关键的其实是实践,多布局和绘制一些view和viewgroup。

android view : 绘制的更多相关文章

  1. 简单研究Android View绘制三 布局过程

    2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...

  2. 简单研究Android View绘制一 测量过程

    2015-07-27 16:52:58 一.如何通过继承ViewGroup来实现自定义View?首先得搞清楚Android时如何绘制View的,参考Android官方文档:How Android Dr ...

  3. Android View绘制原理分析

    推荐两篇分析view绘制原理比较好的文章,感谢作者的分享. <Android应用层View绘制流程与源码分析> <View 绘制流程>

  4. Android View绘制过程

    Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...

  5. Android View绘制流程

    框架分析 在之前的下拉刷新中,小结过触屏消息先到WindowManagerService(Wms)然后顺次传递给ViewRoot(派生自Handler),经decor view到Activity再传递 ...

  6. Android View绘制13问13答

    1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view? 答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程.draw ...

  7. Android View 绘制过程

    Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...

  8. Android View 绘制刷新流程分析

    Android中对View的更新有很多种方式,使用时要区分不同的应用场合.1.不使用多线程和双缓冲      这种情况最简单,一般只是希望在View发生改变时对UI进行重绘.你只需显式地调用View对 ...

  9. Android View 绘制流程(Draw) 完全解析

    前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程.测量流程决定了View的大小,布局流程决定了View的位 ...

  10. 简单研究Android View绘制二 LayoutParams

    2015-07-28 17:23:20 本篇是关于LayoutParams相关 ViewGroup.LayoutParams文档解释如下: LayoutParams are used by views ...

随机推荐

  1. uva 820(最大流)

    最大流的裸题,直接贴了模板. #include <cstdio> #include <iostream> #include <sstream> #include & ...

  2. CSS3让一段文字多余的用省略号表示,当鼠标移动上去的时候显示全部文字

    <style type="text/css"> div { width:100px; overflow:hidden; white-space:nowrap; text ...

  3. nodeType的意思

    nodeType是用来获得当前节点对象的类型.nodeType 属性可返回节点的类型.元素element   1   属性attr   2   文本text   3   注释comments   8 ...

  4. blade and soul races guide

    Race Four races are available for those who wish to choose the path of martial arts: the careful Gon ...

  5. UIImage

    //设置UIImage的圆角 + (UIImage *)imageNamed:(NSString *)name size:(CGSize)size cornerRadius:(CGFloat)corn ...

  6. Entity Framework – (复数)Plural and (单数)Singular 表名Table names

    By default, the Entity Framework will assume that all of the names of your tables in your database a ...

  7. 使用nodejs调用微信发送红包

    前置条件:申请微信发送红包的账户及其权限 依赖 blueimg-md5和 xmlreader 库 /common/weixin.js 源码 /** * Created by chent696 on 2 ...

  8. 【 2013 Multi-University Training Contest 4 】

    HDU 4632 Palindrome subsequence dp[x][y]表示区间[x,y]构成回文串的方案数. 若str[x]==str[y],dp[x][y]=dp[x+1][y]+dp[x ...

  9. (BFS)aoj0558-Cheese

    题目地址 根据题意,必须按从1吃到n的顺序.建立vi数组记录去没去过某一点,从起点向四周搜索,合法且未去过就入队列.每当找到符合此时应吃的位置,就将这个位置改为'.'并刷新vi数组,清空队列(因为必须 ...

  10. Haskell Platform (windows)

    一.下载地址:https://www.haskell.org/platform/windows.html Haskell Platform 整合了 Glasgow Haskell Compiler,W ...