Skip to content

Instantly share code, notes, and snippets.

@ixiyang
Created December 12, 2013 03:25
Show Gist options
  • Save ixiyang/7922758 to your computer and use it in GitHub Desktop.
Save ixiyang/7922758 to your computer and use it in GitHub Desktop.
android view 绘制流程
关于view的绘制流程
View
ViewParent(interface)
ViewGroup(extends View implements ViewParent)
ViewRoot(implements ViewParent)
Being a root parent of all views in the activity, the ViewRootschedules traversals of all the views in
order to first lay them out at the right place with the right size; this is called the layout phase. The
ViewRoot then traverses the view hierarchy to draw them; this phase is called the drawing phase.
We will talk about each of these phases now.(ViewRoot是每个activity视图层级的最顶层。负责整个视图的layout和draw两个过程)
Layout Phase: Measurement and Layout
布局阶段:确定视图层级中视图的大小和位置。
Measure pass
The measure pass is implemented by the measure( ) function of the Viewclass.The signature of this function is
public final void measure(int widthMeasureSpec, int heightMeasureSpec)
Make a note of this method’s signature. This signature will help you to easily locate this method
measure( ) in the source code of the large View.javasource file. This method, measure( ), does some
housekeeping and calls the onMeasure( ) of the derived views. The derived views need to set their
dimensions by calling setMeasuredDimension(). These measured dimensions set on each view are
then subsequently used in the layout pass. In this context, your primary override is View.onMeasure().
Keep in mind that there is a default implementation for onMeasure(). The default implementation of
onMeasure( ) decides the size of your view based on suggestions from the layout files, including an
exact size passed in. We will cover this later in the chapter.
Although it is the onMeasure( ) that you care about when you are a creating custom view like the
CircleView, there are times when measure( ) is important as well. If the inherited custom view is a
collection of other views, as in a ViewGroup, then you need to call measure( ) on child views in your
onMeasure( ) method. The signature of measure( ) earlier clearly supports the idea that you can’t
override it by being final, but you are expected to call it by being public. We will cover the measure( )
method arguments widthMeasureSpecand heightMeasureSpecwhen we work with onMeasure()later
in this chapter.
Layout pass
After the measure pass, each view knows its dimensions. The control then passes to the layout pass.
This layout pass is implemented in the layout( ) method, whose signature in the base Viewclass is:
public void layout(int left, int top, int right, int bottom)
Much like the measure( ) method, the layout( ) method carries out an internal protocol for the base
Viewand result in calling the overridden methods in Listing 1-1, in that order.
Listing 1-1. Overridden Methods Called by a View’s Layout( ) Method
protected void onSizeChanged(int w, int h, int oldw, int oldh);
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
The layout pass, implemented in layout( ), will take the dimensions measured by the measure
pass into account and give out the starting position for each view and the dimension each view
needs to use. The base layout( ) method actually sets these dimensions on the view on which it is
called. It then calls the onSizeChanged( ) if there is actually a change in size or position. The default
implementation of onSizeChanged( ) exists in the Viewclass but it is a no-op.
After calling the onSizeChanged( ) method, the layout( ) method calls the onLayout( ) to allow
for something like a view group to call layout( ) on its children. The default implementation for
onLayout( ) exists but it is a no-op. To apply this to our CircleView, we don’t need to do anything in
the onLayout( ) because our position and dimensions are already fixed, and we have no children to
advise their layouts by calling their layout( ) method.
Once both of the passes of the layout phase are completed, the traversal initiated by the view root
will move to the drawing phase.
Drawing Phase: Mechanics of onDraw
The draw traversal is implemented in the View's draw( ) method. The protocol implemented by this
method is:
Draw the background
Draw view's content by delegating to onDraw()
Draw children by delegating to dispatchDraw()
Draw decorations such as scroll bars
Because the draw traversal happens after the layout traversal, you already know the position and the
size of your views. If your view like the CircleViewdoesn’t have children, you don’t care much about
dispatchDraw( ). The default implementation for this method in the base Viewclass exists but is empty.
You could ask: If my custom view has children, why am I not choosing to draw them in onDraw?
Perhaps because, in a framework, the base class View'sfixed protocol of draw( ) may choose
to do something between your onDraw( ) and your children’s onDraw( ). So, it is suggested to the
programmer, by dispatchDraw( ) of the View, that the View’s drawing is complete and the derived
implementation could choose whatever is needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment