1. 程式人生 > >Android View繪制知識問答

Android View繪制知識問答

oid 不同 無法獲得 code pos ren ecs post 基本

技術分享

  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() {

[email protected]

  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 這個標誌位 默認一般都是關閉的。

Android View繪制知識問答