Custom Views - II
Android #android #viewsThis is part 2 of two part series
In part 1, I have discussed core view classes and view types of view constructor. This article focuses on view drawing in its layout in parent view.
At high level, a view is created in two phases.
- Layout Phase
- Drawing Phase
Layout Phase
In layout phase, view parent determines the size and layout of a view, it calculates the size of view and place for laying out view. Layout phase is completed in 2 passes.
- Measure Pass
- Layout Pass
Measure Pass
In measure pass, size of a view is calculated (when it wants to know how big a view can be). It starts when a view parent calls
method of view with appropriate MeasureSpecs
. This method does some work and calls
in custom view.
MeasureSpecs
Parameters passed to onMeasure(...)
are special parameters. They have integer
type but they are actually two parameters encoded
in a single integer. Each parameter has a mode and size value and these values can be retrieved by passing it
to MeasureSpec.getMode(int)
and MeasureSpec.getSize(int)
.
MeasureSpecs Modes
Mode gives you a clue about how big a view should be. Mode can be one of the following
MeasureSpec.EXACTLY
This mode tells that parent has measure the size of child view and view should have this size. onMeasure
is called with this mode
when view is specified in xml
with size equals to match_parent
or exact size in dps e.g. 40dp.
MeasureSpec.AT_MOST
onMeasure
is called with his mode bit if view is specified in xml
with size equals to wrap_content
. With this mode bit, android tells that
I have this size and you can draw your view with in this size.
MeasureSpec.UNSPECIFIED
This mode is used when android system wants to query how big this view can be. It’s our responsibliy to provide the system with appropriate size.
Setting size in onMeasure(...)
In measure pass, after calling onMeasure
, parent views expects us to set the size of view using
After calculating size (based on mode bit or any other logic) you must pass this size to parent using above method, failing to call
this method will trigger IllegalStateException
at runtime.
Default implementation of onMeasure()
The default implementation of onMeasure
calls setMeasuredDimension
by getting width and height from getSuggestedMinimumWidth()
and getSuggestedMinimumHeight()
.
Note that getDefaultSize
returns the same size for both MeasureSpec.AT_MOST
and MeasureSpec.EXACTLY
.
Layout Pass
Layout pass sets the size of view by using dimensions set in onMeasure
. This pass is started when parent view calls layout(...)
method
of view followed by calling onLayout(...)
in derived view.
After setting the size on view, it calls onSizeChanged(..)
if the size of view is changed.
Default implementation of both onSizeChanged
and onLayout
is no-op.