Android View绘制知识问答

  1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view?

  答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。

 

  2.view的测量宽高和实际宽高有区别吗?

  答:基本上百分之99的情况下都是可以认为没有区别的。有两种情况,有区别。第一种 就是有的时候会因为某些原因 view会多次测量,那第一次测量的宽高 肯定和最后实际的宽高 是不一定相等的,但是在这种情况下

  最后一次测量的宽高和实际宽高是一致的。此外,实际宽高是在layout流程里确定的,我们可以在layout流程里 将实际宽高写死 写成硬编码,这样测量的宽高和实际宽高就肯定不一样了,虽然这么做没有意义 而且也不好。

 

  3.自定义view中 如果onMeasure方法 没有对wrap_content 做处理会发生什么?为什么?怎么解决?

  答:如果没有对wrap_content做处理 ,那即使你在xml里设置为wrap_content.其效果也和match_parent相同。看问题4的分析。我们可以知道view自己的layout为wrap,那mode就是at_most(不管父亲view是什么specmode).

  这种模式下宽高就是等于specSize(getDefaultSize函数分析可知),而这里的specSize显然就是parentSize的大小。也就是父容器剩余的大小。那不就和我们直接设置成match_parent是一样的效果了么?

  解决方式就是在onMeasure里 针对wrap 来做特殊处理 比如指定一个默认的宽高,当发现是wrap_content 就设置这个默认宽高即可。

 

  4.ViewGroup有onMeasure方法吗?为什么?

  答:没有,这个方法是交给子类自己实现的。不同的viewgroup子类 肯定布局都不一样,那onMeasure索性就全部交给他们自己实现好了。

 

  5.为什么在activity的生命周期里无法获得测量宽高?有什么方法可以解决这个问题吗?

  答:因为measure的过程和activity的生命周期 没有任何关系。你无法确定在哪个生命周期执行完毕以后 view的measure过程一定走完。可以尝试如下几种方法 获取view的测量宽高。

//重写activity的这个方法

  public void onWindowFocusChanged(boolean hasFocus) {

  super.onWindowFocusChanged(hasFocus);

  if (hasFocus) {

  int width = tv.getMeasuredWidth();

  int height = tv.getMeasuredHeight();

  Log.v("burning", "width==" + width);

  Log.v("burning", "height==" + height);

  }

  }

  或者重写这个方法

@Override

  protected void onStart() {

  super.onStart();

  tv.post(new Runnable() {

  @Override

  public void run() {

  int width = tv.getMeasuredWidth();

  int height = tv.getMeasuredHeight();

  }

  });

  }

 

  6.layout和onLayout方法有什么区别?

  答:layout是确定本身view的位置 而onLayout是确定所有子元素的位置。layout里面 就是通过serFrame方法设设定本身view的 四个顶点的位置。这4个位置以确定 自己view的位置就固定了

  然后就调用onLayout来确定子元素的位置。view和viewgroup的onlayout方法都没有写。都留给我们自己给子元素布局

 

  7.draw方法 大概有几个步骤?

  答: 一共是4个步骤, 绘制背景———绘制自己——–绘制chrildren—-绘制装饰

 

  8.setWillNotDraw方法有什么用?

  答:这个方法在view里。

  

/**

  * If this view doesn't do any drawing on its own, set this flag to

  * allow further optimizations. By default, this flag is not set on

  * View, but could be set on some View subclasses such as ViewGroup.

  *

  * Typically, if you override {@link #onDraw(android.graphics.Canvas)}

  * you should clear this flag.

  *

  * @param willNotDraw whether or not this View draw on its own

  */

  public void setWillNotDraw(boolean willNotDraw) {

  setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);

  }

 

  用于设置标志位的 也就是说 如果你的自定义view 不需要draw的话,就可以设置这个方法为true。这样系统知道你这个view 不需要draw 可以优化执行速度。viewgroup 一般都默认设置这个为true,因为viewgroup多数都是只负责布局

  不负责draw的。而view 这个标志位 默认一般都是关闭的。

posted @ 2017-05-05 18:43  风也不知道往哪吹  阅读(131)  评论(0编辑  收藏  举报