28
Android drawing & graphics API JorgeCastilloPrz @JorgeCastilloPr [email protected] Jorge Castillo Android Engineer at

Android drawing and graphics API

Embed Size (px)

Citation preview

Android drawing & graphics API

JorgeCastilloPrz

@JorgeCastilloPr

[email protected]

Jorge Castillo

Android Engineer at

We are hiringhttps://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

?