Android drawing & graphics API
JorgeCastilloPrz
@JorgeCastilloPr
jorge.castillo.prz@gmail.com
Jorge Castillo
Android Engineer at
We are hiring
https://www.jobandtalent.com/es/careers
We are hiring!
http://www.jobandtalent.com/es/careers
Inspired by... ...the community
Custom Views
● Good way to wrap drawing logic semantically
● Simplify layout composition
● Extend from View / ViewGroup or whatever fits better
● Custom attributes to customize behavior
● Use <merge> tag on layout root (performance)
How Android draws its Views
● It requests the layout’s root node to measure and draw it’s tree
● Tree traversal is pre-order
○ Parents are drawn before their children
○ Siblings drawn in the order they are in the tree
● ViewGroups are responsible for requesting
its children to be drawn
● Every View is responsible for drawing itself F, B, A, D, C, E, G, I, H
Drawing steps
● Measure pass - measure(int, int)
● Layout pass - layout(int, int, int, int)
The draw itself is internally divided in two steps:
measure(int, int)
● Top to bottom
● At the end, getMeasuredWidth() and getMeasuredHeight() must be set for
current view and all its descendants
● Each view pushes dimension specifications down the tree during recursion
● Measured width and height must respect constraints imposed by parent
● A parent may call measure() more than once on its children. (If the children
does not agree on dimensions among themselves).
(1/3)
measure(int, int)
● MeasureSpec are used to push requirements down the tree. Three modes
available:
○ UNESPECIFIED: Used by parents to determine the desired dimen of a
child. (LinearLayout calls measure() on its child with a width of 240 and
height UNESPECIFIED to find out how tall the child would be for an
exact given width)
○ EXACTLY: Used by parent to impose exact size on the child
○ AT_MOST: Used by the parent to impose a maximum size on the child
(2/3)
● MeasureSpec are implemented as ints to reduce object allocation
● Class MeasureSpec is used to pack / unpack <size, mode> tuples into the
given int arguments
● MeasureSpec.getMode(int)
● MeasureSpec.getSize(int)
● MeasureSpec.makeMeasureSpec(int size, int mode) to create a new one
measure(int, int) (3/3)
layout(int, int, int, int)
● Top to bottom
● To assign position to a view and all its descendants
● Each parent is responsible for positioning all of its children using the sizes
computed in the measure pass
● Each parent calls layout() on all of its children
● Four given int arguments are the Left, Top, Right and Bottom positions,
relative to the view’s parent
More about drawing
● Override onSizeChanged() to update your view calculations,
don’t do it in the onDraw() method
● 16 ms / 60 fps every drawing cycle for smoothness
● Update the drawing logic according to states
● You can force a View to draw calling invalidate()
● You can force init the layout pass using requestLayout()
● Keep an eye on overdraw
Detecting Overdraw
● When a time frame of pixels are drawn
multiple times (more rendering work than
necessary)
● Enable “Show overdraw areas” in your
developer console
● Some overdraw is unavoidable. Try to get
mostly true color or 1X as maximum
Some causes
● Multiple full screen background
○ DecorView theme bg can be removed
(after the brand screen is gone):
getWindow().setBackgroundDrawable(null)
● Backgrounds behind avatars to mimic borders
● View hierarchy too deep (Flatten it as much as
possible. Use Hierarchy Viewer to check it)
What about the
Graphics API?
PaintCanvas
About Canvas
● Draw to Canvas when your View needs to re-draw so often.
● You can use it into a View’s onDraw() method or into SurfaceView /
TextureView
● TetureView is like a SurfaceView but behaves as a View, and not just as a
dumb Surface. So it can be moved, transformed, animated… etc.
● SurfaceView and TextureView perform draws to the Canvas as fast as your
thread is capable of
(1/3)
About Canvas
● Canvas relies on underlying Bitmap
● To create a new Canvas from zero you need to provide it
(2/3)
● Multiple clipping and drawing methods
● Every drawing method receives a Paint
About the Paint
● Paint is our drawing tool. Like a brush.
● Paints are configured properly to be used in canvas methods
AndroidFillableLoaders
https://github.com/JorgeCastilloPrz/AndroidFillableLoaders
http://jorgecastillo.xyz
Originally made by Pol Quintana (@poolqf) for iOS
https://github.com/poolqf/FillableLoaders
Two steps
● Stroke animation
Two steps
● Filling animation
ClippingTransform
● Every onDraw() tick we draw depending o the current phase
○ build clipping path
○ apply an offset for the height depending on the phase
○ apply the clipping Path
questions
?

Android drawing and graphics API

  • 1.
    Android drawing &graphics API JorgeCastilloPrz @JorgeCastilloPr jorge.castillo.prz@gmail.com Jorge Castillo Android Engineer at
  • 2.
  • 3.
  • 4.
  • 5.
    Custom Views ● Goodway to wrap drawing logic semantically ● Simplify layout composition ● Extend from View / ViewGroup or whatever fits better ● Custom attributes to customize behavior ● Use <merge> tag on layout root (performance)
  • 6.
    How Android drawsits Views ● It requests the layout’s root node to measure and draw it’s tree ● Tree traversal is pre-order ○ Parents are drawn before their children ○ Siblings drawn in the order they are in the tree ● ViewGroups are responsible for requesting its children to be drawn ● Every View is responsible for drawing itself F, B, A, D, C, E, G, I, H
  • 7.
    Drawing steps ● Measurepass - measure(int, int) ● Layout pass - layout(int, int, int, int) The draw itself is internally divided in two steps:
  • 8.
    measure(int, int) ● Topto bottom ● At the end, getMeasuredWidth() and getMeasuredHeight() must be set for current view and all its descendants ● Each view pushes dimension specifications down the tree during recursion ● Measured width and height must respect constraints imposed by parent ● A parent may call measure() more than once on its children. (If the children does not agree on dimensions among themselves). (1/3)
  • 9.
    measure(int, int) ● MeasureSpecare used to push requirements down the tree. Three modes available: ○ UNESPECIFIED: Used by parents to determine the desired dimen of a child. (LinearLayout calls measure() on its child with a width of 240 and height UNESPECIFIED to find out how tall the child would be for an exact given width) ○ EXACTLY: Used by parent to impose exact size on the child ○ AT_MOST: Used by the parent to impose a maximum size on the child (2/3)
  • 10.
    ● MeasureSpec areimplemented as ints to reduce object allocation ● Class MeasureSpec is used to pack / unpack <size, mode> tuples into the given int arguments ● MeasureSpec.getMode(int) ● MeasureSpec.getSize(int) ● MeasureSpec.makeMeasureSpec(int size, int mode) to create a new one measure(int, int) (3/3)
  • 12.
    layout(int, int, int,int) ● Top to bottom ● To assign position to a view and all its descendants ● Each parent is responsible for positioning all of its children using the sizes computed in the measure pass ● Each parent calls layout() on all of its children ● Four given int arguments are the Left, Top, Right and Bottom positions, relative to the view’s parent
  • 13.
    More about drawing ●Override onSizeChanged() to update your view calculations, don’t do it in the onDraw() method ● 16 ms / 60 fps every drawing cycle for smoothness ● Update the drawing logic according to states ● You can force a View to draw calling invalidate() ● You can force init the layout pass using requestLayout() ● Keep an eye on overdraw
  • 14.
    Detecting Overdraw ● Whena time frame of pixels are drawn multiple times (more rendering work than necessary) ● Enable “Show overdraw areas” in your developer console ● Some overdraw is unavoidable. Try to get mostly true color or 1X as maximum
  • 15.
    Some causes ● Multiplefull screen background ○ DecorView theme bg can be removed (after the brand screen is gone): getWindow().setBackgroundDrawable(null) ● Backgrounds behind avatars to mimic borders ● View hierarchy too deep (Flatten it as much as possible. Use Hierarchy Viewer to check it)
  • 16.
  • 17.
  • 18.
    About Canvas ● Drawto Canvas when your View needs to re-draw so often. ● You can use it into a View’s onDraw() method or into SurfaceView / TextureView ● TetureView is like a SurfaceView but behaves as a View, and not just as a dumb Surface. So it can be moved, transformed, animated… etc. ● SurfaceView and TextureView perform draws to the Canvas as fast as your thread is capable of (1/3)
  • 19.
    About Canvas ● Canvasrelies on underlying Bitmap ● To create a new Canvas from zero you need to provide it (2/3) ● Multiple clipping and drawing methods ● Every drawing method receives a Paint
  • 21.
    About the Paint ●Paint is our drawing tool. Like a brush. ● Paints are configured properly to be used in canvas methods
  • 23.
  • 24.
    Originally made byPol Quintana (@poolqf) for iOS https://github.com/poolqf/FillableLoaders
  • 25.
  • 26.
  • 27.
    ClippingTransform ● Every onDraw()tick we draw depending o the current phase ○ build clipping path ○ apply an offset for the height depending on the phase ○ apply the clipping Path
  • 28.