It’s the arts!Playing with the Android canvas
(or Let’s have a pretext to vandalize art)
Today
Introduction to canvasComposing and transforming
Animations!
Today
Some art vandalization!
But first, setup things:http://sergiandreplace.com/
canvas
IntroducingThe Canvas1
How we paint things in Android?
animate
drawtransform
composite
Open GL
(too complex)
Renderscript(using a hammer to crack a nut)
(and not really for drawing)
Canvas(quick and dirty)
What is exactly a “canvas”?
A Canvas works for you as a pretense, or interface, to the actual surface upon which your graphics will be drawn — it holds all of your
"draw" calls
Tl;dr: Canvas is the class that translates drawing actions into a
Bitmap
To draw something you need 4 components
(almost always)
A Bitmap to hold the pixels
a Canvas to host the draw calls(writing into the bitmap)
a drawing primitive (e.g. Rect, Path, text, Bitmap)
and a Paint (to describe the colors and styles for
the drawing)
Let’s put a smile on that face
Oh, hello beauty!
Remember
Bitmap + Canvas + Paint +Primitive =
Drawing
Let’s improve that smile
Much better,but…
a bit too straight
RectF allows to reuse coordinates
In this case, the Paint is not needed
Here comes the cape crusader!
Let’s get crazy with the rects!
Let’s talk about Bitmaps
A loaded Bitmap is immutableWe can’t draw in it!
Making it mutable
Making it mutable
What?
Bitmaps must be recycled
Recycle marks it as GCable
Still exists, but we can’t draw
Stored in memory with no compression
java.lang.OutOfMemoryError(boo!)
Why to load a huge bitmapif target draw is small?
Branch 1_03_Bitmaps
Composing&
Transforming2
Painting on the activity is cool, but…
Painting views is cooler
Anatomy of a drawing view
1. Create needed objects2. Measure
3. Draw accordingly4. Repeat 2 & 3 when needed
The onDraw method
onDraw is executed everytime the view
needs to be redrawn(or a part of it)
We can request a onDraw with invalidate()
(or postInvalidate if not in UI thread)
onDraw receives a ready-to-use-canvas
MyFirstDrawingView extends from ImageView
But it adds no behaviour. To work!
Understand drawing order
1. ImageView add src
1. ImageView add src
2. MyFirstDrawingView adds a Vignette
3. View class draws background
1. ImageView add src
2. MyFirstDrawingView adds a Vignette
3. View class draws background
1. ImageView add src
2. MyFirstDrawingView adds a Vignette
Introducing Shaders
Basically, shaders modify the behaviour
of Paint object
BitmapShaderAllows to tile a Bitmap
LinearGradientRadialGradientSweepGradient
Guess what they do…
ComposeShader allows to mix two shaders
with an Xfermode
(a really crazy thing)
Paint.setShader(shader)
Let’s combine this!
We want our view to
vignette the image set in the layout
You have to:Create a RadialGradient
(psst, getMeasuredHeight & getMeasuredWidth)
Assign to the Paint objectUse canvas.drawPaint(Paint) to fill it
Pro:Avoid instantiate in the
onDrawMethod(onSizeChanged is your friend)
Use the drawable size, not the View size
Check ScaleMode and Padding behaviour
And now PorterDuffXMode
PorterDuffModes define images will blend
Don’t worry, trial and error
We could also save a layer
Saving layers allows us to make transformations
ExampleSave layer
Transform canvas 45ºDraw square
Restore canvas
More on transformations later on
We can setup a Paint on savingIt will be applied on restoring
Branch 2_03_apples_on_apples
Create a new bitmap to hold the imageCreate a temporary canvas for it
Draw the imageView image on the canvasSave the canvas using a paint with the
PorterDuffsetup the bounds of the drawable maskDraw the mask on the temporary canvas
Restore the temporary canvasDraw the bitmap on the real canvas
Pro:Optimize it to avoid instatiation in
the onDrawPlay around with ratios
Mainly matrixes and camera
Stoping too obvious jokes before is too late
Remember matrixes from school?
Haha. Don’t worry
But rememberOperations order is important
Matrixes are used forTranslateRotateScaleSkew
ButMatrix.setRotateMatrix.setScale
Only scales
We must use preOperationand postOperation
to concatenat
SoMatrix.preRota
teMatrix.setScale
Rotates and scales
SoMatrix.setRotat
eMatrix.postScal
eRotates and
scales
Canvas has unity matrix by default
Translate+
rotate
Rotate +
translate
Translate+
rotate
Rotate +
translate
Translate+
rotate
Rotate +
translate
Translate+
rotate
Rotate +
translate
Translate+
rotate
Rotate +
translate
We canCanvas.save()
Canvas.setMatrix(matrix)Canvas.drawSomething()
Canvas.restore()
OrDrawBitmap with matrix
Cameras allow us to create 3D matrixes
So 3D transformations(axes x, y and z + perspective)
We perform transformations on camera
And then, we get the corresponding matrix
First part objectiveMake an image turn
You have to:Calculate centerCreate a matrix
Set the rotation of the matrixCreate a new Bitmap as big as view
Create the canvas of that BitmapDraw image on the canvas with the
matrixDraw the resulting bitmap on the
main canvas
Pro:Connect a seekBar with the rotation
(wow!)Do it without and with optimization
(is it noticeable?)
All these operations and stuff is cute
Combined are WOW!
We are not going to talk about Animation or Animator class
But how to move all the things we learned
Basically, a onPaint calling invalidate()
Things to keep in mind
We want to achieve as FPS as possible
NO INSTATIATION!!
Flags everywhere!Animating
StartedFolded
…
Create appropiate flags for the status
(boolean or enum, up to you)
Create controls methods(start, stop, rewind, whatever)
Time between onDraw calls changes
startTimedeltaTimeduration
System.currentTimeInMillis
deltaTime = System.currentTimeMillis() - startTime;
progress = (float) deltaTime / duration);
Animation pattern(well, my pattern)
Make the methods setup the states
If/else treating states
Keep in mind what to draw after& before the animation
Cache, cache and cache
Include also animating states
Animating states should change flags
and/or call invalidate
Animating states must calculate progress
Used to add realism to the animations
Time
Animation progress
Boooooooooooring
Time
Animation progress
Oooooooh!
Time
Animation progress
OOOOOOOOOOHHH!!!!
Time
Animation progress
So, interopolators are just functions
f(delta time) = interpolated time
deltaTime = System.currentTimeMillis() - startTime;
progress = (float) deltaTime / duration);
deltaTime = System.currentTimeMillis() - startTime;
interpolatedTime = interpolator.getInterpolation ((float) deltaTime / duration);
Newspaper effect!
Newspaper effect!
Follow the pattern and fill it up comments
Pro:Make things parametized
Add stop/pauseMake real effect (add scale and
alpha)
Did you finish the exercise?
So we are finished
There are many other things in Canvas
Just check drawing text stuff
Whoever made the TextView is my hero
Whoever made EditText is my God
Hope you enjoyed
Willing to see the things you make with all this
Share them in the GDG group!