Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vectorial Victories - Android Makers 2018 - Paris

Vectorial Victories - Android Makers 2018 - Paris

Tired of having to duplicate all your assets in order to manage Android's densities? Vector Drawables are here to save the day!

Except... it is not that easy. There are some nasty traps you need to know in order to really take advantage of this format.

We will see how vectorial drawing works, how it has been adapted to Android and finally one of its biggest strengths: animations!

François Blavoet

April 24, 2018
Tweet

More Decks by François Blavoet

Other Decks in Programming

Transcript

  1. Goal Understand when and how to use Vector drawables and

    how to use them to their fullest. Learn how to deal with common pain points.
  2. First, there were rasters Raster : bitmap / png /

    jpg / webp / … • An asset that describes it’s content as an array of pixels • Works great for images • Can be very heavy • Need to be duplicated for each density
  3. Then, came SVGs Scalable Vector Graphics • Describes curves that

    can be rendered in any size • Infinitely scalable • Very nimble and don’t have to be duplicated • Some bonus features you can’t achieve with rasters
  4. What’s in there ? <svg fill="#ffffff" height="24" viewBox="0 0 24

    24" width="24" xmlns="http://www.w3.org/2000/svg"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/> </svg>
  5. • viewBox : size of the canvas where you describe

    the curves of this vector • height/width : size in pixel of this svg when rendered, ≠ viewBox • fill : color fill for this vector/path • path : curve to draw on the screen <svg fill="#ffffff" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/> </svg>
  6. <svg fill=“#ffffff” height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> <path

    d="M0 0h24v24H0z" fill="none"/> <path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/> </svg>
  7. A path you said ? First instruction : Move <path

    d="M2 5”/> moves the painting cursor somewhere on the canvas
  8. A path you said ? Line <path d="M2 5 l8

    0”/> draws a line starting from the current end of the curve
  9. A path you said ? Line <path d="M2 5 l8

    0”/> draws a line starting from the current end of the curve
  10. A path you said ? Line <path d="M2 5 l8

    0 L 8 0”/> draws a line starting from the current end of the curve
  11. l vs L • Upper case : absolute coordinates •

    lower case : relative coordinates
  12. A path you said ? Line <path d="M2 5 l8

    0 L 8 0”/> draws a line starting from the current end of the curve
  13. A path you said ? closepath <path d="M2 5 l8

    0 L 8 0 z"/> closes the current curve with a straight line to its starting point
  14. A path you said ? horizontal and vertical lines <path

    d="M2 5 l8 0 L 8 0 z
 M 2 10 h 2"/>
  15. A path you said ? horizontal and vertical lines <path

    d="M2 5 l8 0 L 8 0 z
 M 2 10 h 2 v -1.5"/>
  16. A path you said ? stroke <path d="M2 5 l8

    0 L 8 0z"
 fill="none" 
 stroke="red" 
 stroke-width="5"/> you can also control how your curves are drawn
  17. you get the idea many more commands are available :

    
 elliptical arc
 rectangle triangle gradient etc
  18. Up to powerful instructions such as Bezier curves <path d=“M93.069,146.642

    c0,0 298.599, -84.231 196.926,1.225”/>
 
 

  19. I thought this was about Android ? <svg fill="#000000" height="24"

    viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/> </svg>
  20. I thought this was about Android ? <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp"

    android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0"> <path android:fillColor="#000000" android:pathData="M12,3v9.28c-0.47,-0.17 -0.97,-0.28 -1.5,-0.28C8.01,12 6,14.01 6,16.5S8.01,21 10.5,21c2.31,0 4.2,-1.75 4.45,-4H15V6h4V3h-7z" /> </vector> <svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/> </svg>
  21. I thought this was about Android ? <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width=“@dimen/material_icon“

    android:height=“@dimen/material_icon" android:viewportHeight="24.0" android:viewportWidth="24.0"> <path android:fillColor="@color/accent" android:pathData=“@string/note_path” /> </vector> <svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/> </svg>
  22. Vector Drawable • That’s an Android resource !
 
 ->

    can be used just as any other drawable
 
 -> can use @color for fills, @string for paths, @dimen for dimensions • It’s NOT an SVG !!! 
 
 -> only a subset of the SVG norm is supported
  23. Performances <?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="108dp" android:height="108dp" android:viewportHeight="108" android:viewportWidth="108">

    <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffffff" android:pathData="M0.996 21l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 21l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffffff" android:pathData="M0.996 15l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 15l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffffff" android:pathData="M0.996 18l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 18l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ff0000" android:pathData="M0.996 21l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 21l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ff0000" android:pathData="M0.996 15l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 15l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ff0000" android:pathData="M0.996 18l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 18l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffed00" android:pathData="M9.996 21l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M9.996 21l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffed00" android:pathData="M9.996 15l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M9.996 15l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffed00" android:pathData="M9.996 18l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M9.996 18l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ff0092" android:pathData="M18.996 21l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M18.996 21l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ff0092" android:pathData="M18.996 15l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M18.996 15l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ff0092" android:pathData="M18.996 18l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M18.996 18l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#bed62f" android:pathData="M27.996 21l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M27.996 21l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#bed62f" android:pathData="M27.996 15l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M27.996 15l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#bed62f" android:pathData="M27.996 18l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M27.996 18l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#00c7f2" android:pathData="M36.996 21l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 21l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#00c7f2" android:pathData="M36.996 15l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 15l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#00c7f2" android:pathData="M36.996 18l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 18l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffffff" android:pathData="M0.996 12l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 12l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffffff" android:pathData="M0.996 9l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 9l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffaaaa" android:pathData="M0.996 12l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 12l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffaaaa" android:pathData="M0.996 9l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M0.996 9l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffc2e5" android:pathData="M18.996 12l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M18.996 12l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffc2e5" android:pathData="M18.996 9l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M18.996 9l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffc2e5" android:pathData="M18.996 6l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M18.996 6l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#ffc2e5" android:pathData="M18.996 3l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M18.996 3l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#dde89b" android:pathData="M27.996 12l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M27.996 12l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#dde89b" android:pathData="M27.996 9l8 0 0 2 -8 0 0 -2z" /> <path android:fillColor="#ffffff" android:pathData="M27.996 9l8 0 0 2 -8 0 0 -2z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#c1f1fc" android:pathData="M36.996 12l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 12l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#c1f1fc" android:pathData="M36.996 9l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 9l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#c1f1fc" android:pathData="M36.996 6l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 6l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#c1f1fc" android:pathData="M36.996 3l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 3l8 0 0 2 -8 0z" /> </group> <group android:translateX="31" android:translateY="36"> <path android:fillColor="#c1f1fc" android:pathData="M36.996 0l8 0 0 2 -8 0z" /> <path android:fillColor="#ffffff" android:pathData="M36.996 0l8 0 0 2 -8 0z" /> </group> <group android:translateX="32" android:translateY="62"> <path android:fillColor="#007feb" android:pathData="M1 0l42 0c0.554 0 1 0.446 1 1l0 8c0 0.554 -0.446 1 -1 1L1 10C0.446 10 0 9.554 0 9L0 1C0 0.446 0.446 0 1 0Z" /> <path android:fillColor="#ffffff" android:pathData="M17.289062 5.6640625q0 0.3164062 -0.128906 0.5654297Q17.03418 6.4785156 16.811523 6.6425781 16.553711 6.8359375 16.243164 6.9179687 15.935547 7 15.460938 7l-1.904297 0 0 -4.3623047 1.693359 0q0.527344 0 0.770508 0.035156 0.246094 0.035156 0.486328 0.1552734 0.249023 0.1259766 0.369141 0.3398438 0.123046 0.2109375 0.123046 0.4833984 0 0.3164062 -0.166992 0.5595703 -0.166992 0.2402344 -0.471679 0.375l0 0.023437q0.427734 0.084961 0.676757 0.3515625 0.251953 0.2666016 0.251953 0.703125zM15.847656 3.8710938q0 -0.1083985 -0.05566 -0.2167969Q15.739258 3.545898 1.7753906q0 -0.2080078 -0.08203 -0.319336 -0.0791 -0.1142578 -0.272461 -0.1699218 -0.131836 -0.038086 -0.363282 -0.041016 -0.231445 -0.00293 -0.483398 -0.00293l-0.246094 0 0 1.0869141 0.08203 0q0.474609 0 0.679687 -0.00293 0.205078 -0.00293 0.37793 -0.076172 0.175781 -0.073242 0.240234 -0.1933593 0.06738 -0.1230469 0.06738 -0.28125z" /> <path android:fillColor="#ffffff" android:pathData="M22.032227 7l-3.155274 0 0 -4.3623047 3.155274 0 0 0.84375 -2.036133 0 0 0.7529297 1.889648 0 0 0.84375 -1.889648 0 0 1.078125 2.036133 0 0 0.84375z" /> <path android:fillColor="#ffffff" android:pathData="M27.141602 3.4814453l-1.362305 0 0 3.5185547 -1.125 0 0 -3.5185547 -1.362305 0 0 -0.84375 3.84961 0 0 0.84375z" /> <path android:fillColor="#ffffff" android:pathData="M32.599609 7l-1.163086 0 -0.301757 -0.8818359 -1.617188 0L29.21582 7l-1.133789 0 1.611328 -4.3623047 1.294922 0L32.599609 7Zm-1.737304 -1.6816406l-0.536133 -1.5644531 -0.536133 1.5644531 1.072266 0z" /> </group> </vector>
  24. Performances <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="108dp" android:height="108dp" android:viewportWidth="108" android:viewportHeight="108"> <path android:pathData="M 33.5

    62 L 75.5 62 C 76.05 62 76.5 62.45 76.5 63 L 76.5 71 C 76.5 71.55 76.05 72 75.5 72 L 33.5 72 C 32.95 72 32.5 71.55 32.5 71 L 32.5 63 C 32.5 62.45 32.95 62 33.5 62 Z" android:fillColor="#007feb"/> <path android:pathData="M 49.8 67.66 C 49.8 67.86 49.75 68.06 49.66 68.23 C 49.58 68.4 49.46 68.53 49.31 68.63 C 49.15 68.77 48.96 68.86 48.75 68.93 C 48.55 68.97 48.29 69 47.97 69 L 59.5 51 Z M 59.5 54 L 67.5 54 L 67.5 56 L 59.5 56 L 59.5 54 Z M 68.5 57 L 76.5 57 39 L 58.5 39 L 58.5 41 L 50.5 41 L 50.5 39 Z M 59.5 48 L 67.5 48 L 67.5 50 L 59………………………” android:fillColor="#ffffff"/> </vector>
  25. Performances ~ > svgo -p 2 sample.svg sample.svg: Done in

    24 ms! 0.269 KiB - 40.4% = 0.16 KiB ~ > avocado ic_add.xml ic_add.xml: Done in 13 ms! 0.303 Kb - 10.6% = 0.271 Kb
  26. Backport time !! defaultConfig { vectorDrawables.useSupportLibrary = true } ->

    VectorDrawableCompat -> AnimatedVectorDrawableCompat