概述

Android中View框架的工作机制中,主要有三个过程:

1、View树的測量(measure)Android View框架的measure机制

2、View树的布局(layout) Android View框架的layout机制

3、View树的绘制(draw)Android View框架的draw机制

View框架的工作流程为:測量每一个View大小(measure)-->把每一个View放置到对应的位置(layout)-->绘制每一个View(draw)。

         本文主要讲述三大流程中的measure过程。

带着问题来思考整个measure过程。

1、系统为什么要有measure过程?

开发者在绘制UI的时候,基本都是通过XML布局文件的方式来配置UI,而每一个View必需要设置的两个群属性就是layout_width和layout_height,这两个属性代表着当前View的尺寸。

官方文档截图:

所以这两个属性的值是必需要指定的,这两个属性的取值仅仅能为三种类型:

                 1、固定的大小。比方100dp。

                 2、刚好包裹当中的内容,wrap_content。

                 3、想要和父布局一样大,match_parent / fill_parent。

因为Android希望提供一个更优雅的GUI框架,所以提供了自适应的尺寸,也就是 wrap_content 和 match_parent 。

试想一下,那假设这些属性仅仅同意设置固定的大小,那么每一个View的尺寸在绘制的时候就已经确定了。所以可能都不须要measure过程。可是因为须要满足自适应尺寸的机制,所以须要一个measure过程。

2、measure过程都干了点什么事?

因为上面提到的自适应尺寸的机制。所以在用自适应尺寸来定义View大小的时候。View的真实尺寸还不能确定。可是View尺寸终于须要映射到屏幕上的像素大小,所以measure过程就是干这件事。把各种尺寸值,经过计算。得到详细的像素值。measure过程会遍历整棵View树,然后依次測量每一个View真实的尺寸。详细是每一个ViewGroup会向它内部的每一个子View发送measure命令,然后由详细子View的onMeasure()来測量自己的尺寸。

最后測量的结果保存在View的mMeasuredWidth和mMeasuredHeight中。保存的数据单位是像素。

3、对于自适应的尺寸机制,怎样合理的測量一颗View树?

系统在遍历完布局文件后,针对布局文件,在内存中生成相应的View树结构,这个时候,整棵View树种的全部View对象,都还没有详细的尺寸,由于measure过程终于是要确定每一个View打的准确尺寸。也就是准确的像素值。

可是刚開始的时候。View中layout_width和layout_height两个属性的值,都仅仅是自适应的尺寸,也就是match_parent和wrap_content,这两个值在系统中为负数。所以系统不会把它们当成详细的尺寸值。所以当一个View须要把它内部的match_parent或者wrap_content转换成详细的像素值的时候。他须要知道两个信息。

        1、针对于match_parent,父布局当前详细像素值是多少,由于match_parent就是子View想要和父布局一样大。

        2、针对wrap_content,子View须要依据当前自己内部的content,算出一个合理的能包裹全部内容的最小值。可是假设这个最小值比当前父布局还大,那不行,父布局会告诉你,我仅仅有这么大,你也不应该超过这个尺寸。

因为树这样的数据结构的特殊性,我们在研究measure的过程时,能够仅仅研究一个ViewGroup和2个View的简单场景。大概示意图例如以下:

也就是说,在measure过程中,ViewGroup会依据自己当前的状况。结合子View的尺寸数据,进行一个综合评定,然后把相关信息告诉子View。然后子View在onMeasure自己的时候,一边须要考虑到自己的content大小,一边还要考虑的父布局的限制信息。然后综合评定,測量出一个最优的结果。

4、那么ViewGroup是怎样向子View传递限制信息的?

谈到传递限制信息。那就是MeasureSpec类了。该类贯穿于整个measure过程。用来传递父布局对子View尺寸測量的约束信息。简单来说,该类就保存两类数据。

                1、子View当前所在父布局的详细尺寸。

                2、父布局对子View的限制类型。

        那么限制类型又分为三种类型:

1、UNSPECIFIED,不限定。

意思就是,子View想要多大,我就能够给你多大,你放心大胆的measure吧,不用管其它的。也不用管我传递给你的尺寸值。(事实上Android高版本号中推荐,仅仅要是这个模式。尺寸设置为0)

                2、EXACTLY,精确的。意思就是。依据我当前的状况,结合你指定的尺寸參数来考虑。你就应该是这个尺寸,详细大小在MeasureSpec的尺寸属性中。自己去查看吧,你也不要管你的content有多大了。就用这个尺寸吧。

                3、AT_MOST,最多的。

意思就是,依据我当前的情况,结合你指定的尺寸參数来考虑,在不超过我给你限定的尺寸的前提下。你測量一个恰好能包裹你内容的尺寸就能够了。

源码分析

在View的源码中,提取到了以下一些关于measure过程的信息。

我们知道。整棵View树的根节点是DecorView,它是一个FrameLayout,所以它是一个ViewGroup。所以整棵View树的測量是从一个ViewGroup对象的measure方法開始的。

View:

1、measure

/** 開始測量一个View有多大,parent会在參数中提供约束信息。实际的測量工作是在onMeasure()中进行的,该方法会调用onMeasure()方法。所以仅仅有onMeasure能被也必需要被override */

public final void measure(int widthMeasureSpec, int heightMeasureSpec);

父布局会在自己的onMeasure方法中。调用child.measure ,这就把measure过程转移到了子View中。

2、onMeasure

/** 详细測量过程,測量view和它的内容。来决定測量的宽高(mMeasuredWidth  mMeasuredHeight )。

该方法中必需要调用setMeasuredDimension(int, int)来保存该view測量的宽高。 */

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec);

子View会在该方法中,依据父布局给出的限制信息,和自己的content大小,来合理的測量自己的尺寸。

3、setMeasuredDimension

/** 保存測量结果 */

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight);

当View測量结束后,把測量结果保存起来,详细保存在mMeasuredWidth和mMeasuredHeight中。

ViewGroup:

1、measureChildren

/** 让全部子view測量自己的尺寸。须要考虑当前ViewGroup的MeasureSpec和Padding。

跳过状态为gone的子view */

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec);-->getChildMeasureSpec()-->child.measure();

測量全部的子View尺寸,把measure过程交到子View内部。

2、measureChild

/** 測量单个View。须要考虑当前ViewGroup的MeasureSpec和Padding。 */

protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec);-->getChildMeasureSpec()-->child.measure();

对每个详细的子View进行測量。

3、measureChildWithMargins

/** 測量单个View,须要考虑当前ViewGroup的MeasureSpec和Padding、margins。 */

protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed);-->getChildMeasureSpec()-->child.measure();

对每个详细的子View进行測量。可是须要考虑到margin等信息。

4、getChildMeasureSpec

/** measureChildren过程中最困难的一部分,为child计算MeasureSpec。该方法为每一个child的每一个维度(宽、高)计算正确的MeasureSpec。目标就是把当前viewgroup的MeasureSpec和child的LayoutParams结合起来。生成最合理的结果。

比方,当前ViewGroup知道自己的准确大小。由于MeasureSpec的mode为EXACTLY,而child希望可以match_parent。这时就会为child生成一个mode为EXACTLY。大小为ViewGroup大小的MeasureSpec。

*/

public static int getChildMeasureSpec(int spec, int padding, int childDimension);

依据当前自身的状况。以及特定子View的尺寸參数,为特定子View计算一个合理的限制信息。

源码:

  1. public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
  2. int specMode = MeasureSpec.getMode(spec);
  3. int specSize = MeasureSpec.getSize(spec);
  4.  
  5. int size = Math.max(0, specSize - padding);
  6.  
  7. int resultSize = 0;
  8. int resultMode = 0;
  9.  
  10. switch (specMode) {
  11. // Parent has imposed an exact size on us
  12. case MeasureSpec.EXACTLY:
  13. if (childDimension >= 0) {
  14. resultSize = childDimension;
  15. resultMode = MeasureSpec.EXACTLY;
  16. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  17. // Child wants to be our size. So be it.
  18. resultSize = size;
  19. resultMode = MeasureSpec.EXACTLY;
  20. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  21. // Child wants to determine its own size. It can't be
  22. // bigger than us.
  23. resultSize = size;
  24. resultMode = MeasureSpec.AT_MOST;
  25. }
  26. break;
  27.  
  28. // Parent has imposed a maximum size on us
  29. case MeasureSpec.AT_MOST:
  30. if (childDimension >= 0) {
  31. // Child wants a specific size... so be it
  32. resultSize = childDimension;
  33. resultMode = MeasureSpec.EXACTLY;
  34. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  35. // Child wants to be our size, but our size is not fixed.
  36. // Constrain child to not be bigger than us.
  37. resultSize = size;
  38. resultMode = MeasureSpec.AT_MOST;
  39. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  40. // Child wants to determine its own size. It can't be
  41. // bigger than us.
  42. resultSize = size;
  43. resultMode = MeasureSpec.AT_MOST;
  44. }
  45. break;
  46.  
  47. // Parent asked to see how big we want to be
  48. case MeasureSpec.UNSPECIFIED:
  49. if (childDimension >= 0) {
  50. // Child wants a specific size... let him have it
  51. resultSize = childDimension;
  52. resultMode = MeasureSpec.EXACTLY;
  53. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  54. // Child wants to be our size... find out how big it should
  55. // be
  56. resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
  57. resultMode = MeasureSpec.UNSPECIFIED;
  58. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  59. // Child wants to determine its own size.... find out how
  60. // big it should be
  61. resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
  62. resultMode = MeasureSpec.UNSPECIFIED;
  63. }
  64. break;
  65. }
  66. return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
  67. }

伪代码:

  1. public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
  2. 获取限制信息中的尺寸和模式。
  3. switch (限制信息中的模式) {
  4. case 当前容器的父容器。给当前容器设置了一个精确的尺寸:
  5. if (子View申请固定的尺寸) {
  6. 你就用你自己申请的尺寸值即可了;
  7. } else if (子View希望和父容器一样大) {
  8. 你就用父容器的尺寸值即可了;
  9. } else if (子View希望包裹内容) {
  10. 你最大尺寸值为父容器的尺寸值。可是你还是要尽可能小的測量自己的尺寸。包裹你的内容就足够了;
  11. }
  12. break;
  13. case 当前容器的父容器。给当前容器设置了一个最大尺寸:
  14. if (子View申请固定的尺寸) {
  15. 你就用你自己申请的尺寸值即可了;
  16. } else if (子View希望和父容器一样大) {
  17. 你最大尺寸值为父容器的尺寸值。可是你还是要尽可能小的測量自己的尺寸。包裹你的内容就足够了;
  18. } else if (子View希望包裹内容) {
  19. 你最大尺寸值为父容器的尺寸值,可是你还是要尽可能小的測量自己的尺寸,包裹你的内容就足够了;
  20. }
  21. break;
  22. case 当前容器的父容器,对当前容器的尺寸不限制:
  23. if (子View申请固定的尺寸) {
  24. 你就用你自己申请的尺寸值即可了;
  25. } else if (子View希望和父容器一样大) {
  26. 父容器对子View尺寸不做限制。
  27. } else if (子View希望包裹内容) {
  28. 父容器对子View尺寸不做限制。
  29. }
  30. break;
  31. } return 对子View尺寸的限制信息;
  32. }

当自己定义View的时候,也须要处理measure过程。主要有两种情况。

1、继承自View的子类。

                须要覆写onMeasure来正确測量自己。最后都须要调用setMeasuredDimension来保存測量结果

一般来说。自己定义View的measure过程伪代码为:

  1. int mode = MeasureSpec.getMode(measureSpec);
  2. int size = MeasureSpec.getSize(measureSpec);
  3.  
  4. int viewSize = 0;
  5.  
  6. swith (mode) {
  7. case MeasureSpec.EXACTLY:
  8. viewSize = size; //当前View尺寸设置为父布局尺寸
  9. break;
  10. case MeasureSpec.AT_MOST:
  11. viewSize = Math.min(size, getContentSize()); //当前View尺寸为内容尺寸和父布局尺寸其中的最小值
  12. break;
  13. case MeasureSpec.UNSPECIFIED:
  14. viewSize = getContentSize(); //内容有多大。就设置尺寸为多大
  15. break;
  16. default:
  17. break;
  18. }
  19.  
  20. setMeasuredDimension(viewSize);

2、继承自ViewGroup的子类。

                不但须要覆写onMeasure来正确測量自己。可能还要覆写一系列measureChild方法,来正确的測量子view。比方ScrollView。或者干脆放弃父类实现的measureChild规则,自己又一次实现一套測量子view的规则,比方RelativeLayout。最后都须要调用setMeasuredDimension来保存測量结果。

一般来说,自己定义ViewGroup的measure过程的伪代码为:

  1. //ViewGroup開始測量自己的尺寸
  2. viewGroup.onMeasure();
  3. //ViewGroup为每一个child计算測量限制信息(MeasureSpec)
  4. viewGroup.getChildMeasureSpec();
  5. //把上一步生成的限制信息。传递给每一个子View,然后子View開始measure自己的尺寸
  6. child.measure();
  7. //子View測量完毕后,ViewGroup就能够获取每一个子View測量后的尺寸
  8. child.getChildMeasuredSize();
  9. //ViewGroup依据自己自身状况,比方Padding等,计算自己的尺寸
  10. viewGroup.calculateSelfSize();
  11. //ViewGroup保存自己的尺寸
  12. viewGroupsetMeasuredDimension();

案例分析

非常多开发者都遇到过这样的需求,就是ScrollView内部嵌套ListView,而该ListView数据条数是不确定的。所以须要设置为包裹内容,然后就会发现ListView就会显示第一行出来。然后就会百度到一条解决方式,继承ListView。覆写onMeasure方法。

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
  4. super.onMeasure(widthMeasureSpec, expandSpec);
  5. }

问题是攻克了。可是非常多开发者并不知道为什么。

以下会从ScrollView和ListView的measure过程来分析一下。

1、为什么会出现上述问题?

备注:截取部分问题相关代码,并非完整代码。

看看ListView的onMeasure:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. final View child = obtainView(0, mIsScrap);
  4. childHeight = child.getMeasuredHeight();
  5. if (heightMode == MeasureSpec.UNSPECIFIED) {
  6. heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2;
  7. if (heightMode == MeasureSpec.AT_MOST) {
  8. // TODO: after first layout we should maybe start at the first visible position, not 0
  9. heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
  10. }
  11. setMeasuredDimension(widthSize, heightSize);
  12. mWidthMeasureSpec = widthMeasureSpec;
  13. }
  14. }

当MeasureSpec mode为UNSPECIFIED的时候,仅仅測量第一个item打的高度,跟问题描写叙述相符。所以我们推測可能是由于ScrollView传递了一个UNSPECIFIED限制给ListView。

再来看ScrollView的onMeasure代码:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  4. }

调用了父类的onMeasure:

看看FrameLayout的onMeasure:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. for (int i = 0; i < count; i++) {
  4. final View child = getChildAt(i);
  5. if (mMeasureAllChildren || child.getVisibility() != GONE) {
  6. measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
  7. }
  8. }
  9. }

调用了measureChildWithMargins。可是由于ScrollView覆写了该方法,所以看看ScrollView的measureChildWithMargins方法:

  1. @Override
  2. protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
  3. int parentHeightMeasureSpec, int heightUsed) {
  4. final int childHeightMeasureSpec =
  5. MeasureSpec.makeSafeMeasureSpec(MeasureSpec.getSize(parentHeightMeasureSpec),
  6. MeasureSpec.UNSPECIFIED);
  7. child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
  8. }

果然,它向ListView的onMeasure传递了一个UNSPECIFIED的限制。

为什么呢,想想,由于ScrollView。本来就是能够在竖直方向滚动的布局,所以。它对它全部的子View的高度就是UNSPECIFIED,意思就是,不限制子View有多高,由于我本来就是须要竖直滑动的,它的本意就是如此,所以它对子View高度不做不论什么限制。

2、为什么这样的解决方法能够解决问题?

看看ListView的onMeasure:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. final View child = obtainView(0, mIsScrap);
  4. childHeight = child.getMeasuredHeight();
  5. if (heightMode == MeasureSpec.UNSPECIFIED) {
  6. heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2;
  7. if (heightMode == MeasureSpec.AT_MOST) {
  8. // TODO: after first layout we should maybe start at the first visible position, not 0
  9. heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
  10. }
  11. setMeasuredDimension(widthSize, heightSize);
  12. mWidthMeasureSpec = widthMeasureSpec;
  13. }
  14. }

仅仅要让heightMode == MeasureSpec.AT_MOST,它就会測量它的完整高度,所以第一个数据,限制mode的值就确定下来了。

第二个数据就是尺寸上限,假设给个200。那么当ListView数据过多的时候。该ListView最大高度就是200了,还是不能全然显示内容,怎么办?那么就给个最大值吧,最大值是多少呢,Integer.MAX_VALUE?

先看一下MeasureSpec的代码说明:

  1. private static final int MODE_SHIFT = 30;
  2. public static final int UNSPECIFIED = 0 << MODE_SHIFT;
  3. public static final int EXACTLY = 1 << MODE_SHIFT;
  4. public static final int AT_MOST = 2 << MODE_SHIFT;

他用最高两位存储mode,用其它剩余未存储size。

所以Integer.MAX_VALUE >> 2,就是限制信息所能携带的最大尺寸数据。所以最后就须要用这两个值做成一个限制信息。传递给ListView的height维度。

也就是例如以下代码:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
  4. super.onMeasure(widthMeasureSpec, expandSpec);
  5. }

自己动手

以下我们自己写一个自己定义的ViewGroup,让它内部的每个子View都垂直排布。而且让每个子View的左边界都距离上一个子View的左边界一定的距离。

而且支持wrap_content。大概看起来例如以下图所看到的:

实际执行效果例如以下图所看到的:

 代码例如以下:

  1. public class VerticalOffsetLayout extends ViewGroup {
  2.  
  3. private static final int OFFSET = 100;
  4.  
  5. public VerticalOffsetLayout(Context context) {
  6. super(context);
  7. }
  8.  
  9. public VerticalOffsetLayout(Context context, AttributeSet attrs) {
  10. super(context, attrs);
  11. }
  12.  
  13. public VerticalOffsetLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  14. super(context, attrs, defStyleAttr);
  15. }
  16.  
  17. @Override
  18. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  19. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  20.  
  21. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  22. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  23. int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  24. int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  25.  
  26. int width = 0;
  27. int height = 0;
  28.  
  29. int childCount = getChildCount();
  30. for (int i = 0; i < childCount; i++) {
  31. View child = getChildAt(i);
  32. ViewGroup.LayoutParams lp = child.getLayoutParams();
  33. int childWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
  34. int childHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
  35. child.measure(childWidthSpec, childHeightSpec);
  36. }
  37.  
  38. switch (widthMode) {
  39. case MeasureSpec.EXACTLY:
  40. width = widthSize;
  41. break;
  42. case MeasureSpec.AT_MOST:
  43. case MeasureSpec.UNSPECIFIED:
  44. for (int i = 0; i < childCount; i++) {
  45. View child = getChildAt(i);
  46. int widthAddOffset = i * OFFSET + child.getMeasuredWidth();
  47. width = Math.max(width, widthAddOffset);
  48. }
  49. break;
  50. default:
  51. break;
  52.  
  53. }
  54.  
  55. switch (heightMode) {
  56. case MeasureSpec.EXACTLY:
  57. height = heightSize;
  58. break;
  59. case MeasureSpec.AT_MOST:
  60. case MeasureSpec.UNSPECIFIED:
  61. for (int i = 0; i < childCount; i++) {
  62. View child = getChildAt(i);
  63. height = height + child.getMeasuredHeight();
  64. }
  65. break;
  66. default:
  67. break;
  68.  
  69. }
  70.  
  71. setMeasuredDimension(width, height);
  72. }
  73.  
  74. @Override
  75. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  76. int left = 0;
  77. int right = 0;
  78. int top = 0;
  79. int bottom = 0;
  80.  
  81. int childCount = getChildCount();
  82.  
  83. for (int i = 0; i < childCount; i++) {
  84. View child = getChildAt(i);
  85. left = i * OFFSET;
  86. right = left + child.getMeasuredWidth();
  87. bottom = top + child.getMeasuredHeight();
  88.  
  89. child.layout(left, top, right, bottom);
  90.  
  91. top += child.getMeasuredHeight();
  92. }
  93. }
  94. }

Android View框架的measure机制的更多相关文章

  1. Android View框架的draw机制

    概述 Android中View框架的工作机制中,主要有三个过程: 1.View树的测量(measure) Android View框架的measure机制 2.View树的布局(layout)Andr ...

  2. Android View框架的layout机制

    概述 Android中View框架的工作机制中,主要有三个过程: 1.View树的测量(measure) Android View框架的measure机制 2.View树的布局(layout)Andr ...

  3. Android View框架总结(八)ViewGroup事件分发机制

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52298780 上篇分析了View的事件分发流程,留了一个问题:如果上 ...

  4. Android View框架总结(四)View布局流程之Measure

    View树的measure流程 View的measures时序图 View布局流程之measure measure过程 View的measure过程 ViewGroup的measure过程 Frame ...

  5. Android View的事件分发机制探索

    概述 Android事件传递机制也是Android系统中比较重要的一块,事件类型有很多种,这里主要讨论TouchEvent的事件在framework层的传递处理机制.因为对于App开发人员来说,理解f ...

  6. Android View框架总结(七)View事件分发机制

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52282833 View布局告一段落,从本篇开始View事件相关分析, ...

  7. Android View框架总结(六)View布局流程之Draw过程

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52236145 View的Draw时序图 ViewRootImpl.p ...

  8. Android view 的事件分发机制

    1 事件的传递顺序是 Activity -> Window -> 顶层View touch 事件产生后,最先由 activity 的 dispatchTouchEvent 处理 /** * ...

  9. Android View框架总结(二)View焦点

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52263256 前言:View框架写到第六篇,发现前面第二篇竟然没有, ...

随机推荐

  1. @property 和@synthesize

    xcode4.4之后,@property包括了@synthesize的功能. 这是编译器的升级. @property有几个作用:1)默认生成一个私有成员变量,并有一个带下划线的别名如_age   2) ...

  2. JS/CSS 响应式样式实例

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. 并发,one

    引言 最近工作当中写了一个有关并发的程序,引起了LZ对并发的强烈兴趣.这一下一发不可收拾,LZ用了一个多星期,看完了这本共280+页的并发编程书.之所以能看这么快,其实这主要归功于,自己之前对并发就有 ...

  4. Altium Designer中画pcb如何隐藏和显示地线

    如何隐藏: 如何显示: 按下N后

  5. 学习笔记:TypeScript入门——基础类型

    前言: TypeScript官网断断续续看过几遍,不知道项目中如何使用,有机会还是要实践一下.现在再把文档上不懂的知识点理一遍. 基础类型 1.什么是元组Tuple? 元组类型允许表示一个已知元素数量 ...

  6. 【Redis】redis的安装、配置执行及Jedisclient的开发使用

    定义: Redis is an open source, BSD licensed, advanced key-value cache and store. It is often referred ...

  7. java程序猿经常使用的工具名称--知道中文意思吗

    在学习java的时候常常会碰到一些单词,可是一般的时候也不是非常在意这个单词的意思,而是能够了解到这个工具或者框架能够做什么就能够了.偶尔总结了一下还蛮有意思的.例如以下, 假设有遗漏,各位能够帮忙补 ...

  8. (转)const char to LPCTSTR不能转化问题

    转: const char to LPCTSTR不能转化问题 Visual C++ 2008里cannot convert parameter 1 from 'const char [13]' to ...

  9. 【BZOJ 3172】单词

    [链接]h在这里写链接 [题意]     给你n个单词;     这n个单词组成了一篇文章;     问你每个单词在这篇文章中出现了多少次.     其中每个单词之间用一个逗号隔开->组成一篇文 ...

  10. UVA Bandwidth

    题目例如以下: Bandwidth  Given a graph (V,E) where V is a set of nodes and E is a set of arcsin VxV, and a ...