Portable Material: Flutter physical models

Portable Material: Flutter physical models

One of the most interesting new technologies to reach the mainstream eye in 2017 is undoubtedly Flutter, a novel cross-platform framework from Google that targets Android, iOS and the oh-so-elusive Fuchsia OS.

Whether you’ve heard of Flutter or not, you will be fascinated by the intriguing design that lurks under the Surface. We’ll dive in to how exactly your Flutter widgets get drawn on screen, from your code all the way down to Skia. Did you know that the UI toolkit in Flutter is based on physical models, and that Material is just one of those? Or that in Flutter the Material and Cupertino (iOS) toolkits share a common heritage in their roots?

---

Presented with Eugenio Marletti at Droidcon Turn 2018.

---

— PDF copy and Keynote source available here: https://www.dropbox.com/sh/fwbmgjvjvfcaptv/AADmDzcmZ90h_jAEB5AHL6wZa?dl=0

4580c218737149bf44d012a110612010?s=128

Sebastiano Poggi

April 19, 2018
Tweet

Transcript

  1. 2.
  2. 3.
  3. 10.
  4. 11.
  5. 12.
  6. 19.
  7. 21.
  8. 24.

    Android Forget about KitKat No ripples No rounded corners No

    elevation/shadows (efficiently) (efficiently)
  9. 25.

    Android Forget about KitKat No ripples No rounded corners No

    elevation/shadows (efficiently) (efficiently)
  10. 30.

    Views 1. Background It’s a Drawable To be precise: ShapeDrawable

    GradientDrawable no, it doesn’t have a gradient all about the stroke naming! right?
  11. 37.

    No drawing done so far Deferred drawing Views compile DisplayLists

    Display lists are sent down to the RenderThread
  12. 47.

    What about the rest? Elevation shadow for example Lives in

    the view’s main RenderNode RenderNode has outline and elevation Outline can be customised ShadowTesselator …and so on
  13. 50.

    64 bit 32 bit WIP API 16+ x86 WIP On

    all supported platforms
  14. 53.

    Platform thread UI thread GPU thread I/O thread ~ main

    thread ~ RenderThread ~ AsyncTask Threading
  15. 54.
  16. 56.
  17. 57.

    import 'package:flutter/material.dart'; void main() => runApp( new Container( alignment: Alignment.center,

    color: const Color.fromARGB(255, 40, 185, 152), child: new SizedBox( width: 240.0, height: 120.0, child: new Card(), ), ), );
  18. 60.

    Composition A build() function import 'package:flutter/material.dart'; @override Widget build(context) =>

    new Container( alignment: Alignment.center, color: const Color.fromARGB(255, 40, 185, 152), child: new SizedBox( width: 240.0, height: 120.0, child: new Card(), ), );
  19. 62.

    import 'package:flutter/material.dart'; void main() => runApp( Container( alignment: Alignment.center, color:

    Colors.grey[50], child: SizedBox( width: 240.0, height: 120.0, child: Card( child: InkWell( onTap: () {}, ), ), ), ), );
  20. 63.

    import 'package:flutter/material.dart'; void main() => runApp( Container( alignment: Alignment.center, color:

    Colors.grey[50], child: SizedBox( width: 240.0, height: 120.0, child: Card( child: _CardContentsPlaceholder(), ), ), ), ); class _CardContentsPlaceholder extends SizedBox {}
  21. 68.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ _CardContentsPlacehol // packages/flutter/lib/src/material/card.dart class Card extends StatelessWidget { Card({ Key key, this.color, this.elevation: 2.0, this.child, }) : super(key: key); final Widget child; final Color color; final double elevation; @override Widget build(context) => Semantics( container: true, child: Container( margin: EdgeInsets.all(4.0), child: Material( color: color, type: MaterialType.card, elevation: elevation, child: child, ), ), ); }
  22. 69.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ _CardContentsPlaceho // packages/flutter/lib/src/material/card.dart class Card extends StatelessWidget { Card({ Key key, this.color, this.elevation: 2.0, this.child, }) : super(key: key); final Widget child; final Color color; final double elevation; @override Widget build(context) => Semantics( container: true, child: Container( margin: EdgeInsets.all(4.0), child: Material( color: color, type: MaterialType.card, elevation: elevation, child: child, ), ), ); }
  23. 70.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ _CardContentsPlace // packages/flutter/lib/src/material/card.dart class Card extends StatelessWidget { Card({ Key key, this.color, this.elevation: 2.0, this.child, }) : super(key: key); final Widget child; final Color color; final double elevation; @override Widget build(context) => Semantics( container: true, child: Container( margin: EdgeInsets.all(4.0), child: Material( color: color, type: MaterialType.card, elevation: elevation, child: child, ), ), ); }
  24. 71.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Material ↳ _CardContentsPlac // packages/flutter/lib/src/material/card.dart class Card extends StatelessWidget { Card({ Key key, this.color, this.elevation: 2.0, this.child, }) : super(key: key); final Widget child; final Color color; final double elevation; @override Widget build(context) => Semantics( container: true, child: Container( margin: EdgeInsets.all(4.0), child: Material( color: color, type: MaterialType.card, elevation: elevation, child: child, ), ), ); }
  25. 72.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Material ↳ _CardContentsPlac // packages/flutter/lib/src/material/card.dart class Card extends StatelessWidget { Card({ Key key, this.color, this.elevation: 2.0, this.child, }) : super(key: key); final Widget child; final Color color; final double elevation; @override Widget build(context) => Semantics( container: true, child: Container( margin: EdgeInsets.all(4.0), child: Material( color: color, type: MaterialType.card, elevation: elevation, child: child, ), ), ); }
  26. 73.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _CardContentsPl // packages/flutter/lib/src/material/card.dart class Card extends StatelessWidget { Card({ Key key, this.color, this.elevation: 2.0, this.child, }) : super(key: key); final Widget child; final Color color; final double elevation; @override Widget build(context) => Semantics( container: true, child: Container( margin: EdgeInsets.all(4.0), child: Material( color: color, type: MaterialType.card, elevation: elevation, child: child, ), ), ); }
  27. 74.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _CardContentsPlace // flutter/packages/flutter/lib/src/material/material.dart class Material extends StatefulWidget { Material({ Key key, this.type: MaterialType.canvas, this.elevation: 0.0, this.color, this.shadowColor: Color(0xFF000000), this.textStyle, this.borderRadius, this.shape, this.animationDuration: kThemeChangeDuration, this.child, }) : assert(type != null), assert(elevation != null), assert(shadowColor != null), assert(!(shape != null && borderRadius != null)), assert(animationDuration != null), assert(!(identical(type, MaterialType.circle) && (borderRadius != null || shape != null))), super(key: key); // ... @override _MaterialState createState() => _MaterialState(); class _MaterialState extends State<Material> with TickerProviderStateMixin { @override Widget build(context) { // ... } }
  28. 75.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _CardContentsPlace // flutter/packages/flutter/lib/src/material/material.dart class _MaterialState extends State<Material> with TickerProviderStateMixin { @override Widget build(context) { // ... } }
  29. 76.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ AnimatedDefaultTextStyle ↳ _CardContentsPlaceholde // flutter/packages/flutter/lib/src/material/material.dart class _MaterialState extends State<Material> with TickerProviderStateMixin { @override Widget build(context) { // ... Widget contents = AnimatedDefaultTextStyle( style: widget.textStyle ?? Theme .of(context) .textTheme .body1, duration: widget.animationDuration, child: widget.child, ); // ... } }
  30. 77.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ AnimatedDefaultTextStyle ↳ DefaultTextStyle ↳ _CardContentsPlacehold // flutter/packages/flutter/lib/src/material/material.dart class _MaterialState extends State<Material> with TickerProviderStateMixin { @override Widget build(context) { // ... Widget contents = AnimatedDefaultTextStyle( style: widget.textStyle ?? Theme .of(context) .textTheme .body1, duration: widget.animationDuration, child: widget.child, ); // ... } }
  31. 78.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ NotificationListener ↳ AnimatedDefaultTextStyle ↳ DefaultTextStyle ↳ _CardContentsPlaceh // flutter/packages/flutter/lib/src/material/material.dart class _MaterialState extends State<Material> with TickerProviderStateMixin { @override Widget build(context) { // ... Widget contents = AnimatedDefaultTextStyle( style: widget.textStyle ?? Theme.of(context).textTheme.body1, duration: widget.animationDuration, child: widget.child, ); final Color backgroundColor = _getBackgroundColor(context); contents = NotificationListener<LayoutChangedNotification>( onNotification: (notification) { _inkFeatureRenderer.currentContext .findRenderObject() ._didChangeLayout(); return true; }, child: _InkFeatures( key: _inkFeatureRenderer, color: backgroundColor, child: contents, vsync: this, ), ); // ... }
  32. 79.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyl ↳ DefaultTextStyle ↳ _CardContentsPlac // flutter/packages/flutter/lib/src/material/material.dart class _MaterialState extends State<Material> with TickerProviderStateMixin { @override Widget build(context) { // ... Widget contents = AnimatedDefaultTextStyle( style: widget.textStyle ?? Theme.of(context).textTheme.body1, duration: widget.animationDuration, child: widget.child, ); final Color backgroundColor = _getBackgroundColor(context); contents = NotificationListener<LayoutChangedNotification>( onNotification: (notification) { _inkFeatureRenderer.currentContext .findRenderObject() ._didChangeLayout(); return true; }, child: _InkFeatures( key: _inkFeatureRenderer, color: backgroundColor, child: contents, vsync: this, ), ); // ... }
  33. 80.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextSt ↳ DefaultTextStyle ↳ _CardContentsPl // flutter/packages/flutter/lib/src/material/material.dart class _MaterialState extends State<Material> with TickerProviderStateMixin { @override Widget build(context) { // ... Widget contents = AnimatedDefaultTextStyle( style: widget.textStyle ?? Theme.of(context).textTheme.body1, duration: widget.animationDuration, child: widget.child, ); final Color backgroundColor = _getBackgroundColor(context); contents = NotificationListener<LayoutChangedNotification>( onNotification: (notification) { _inkFeatureRenderer.currentContext .findRenderObject() ._didChangeLayout(); return true; }, child: _InkFeatures( key: _inkFeatureRenderer, color: backgroundColor, child: contents, vsync: this, ), ); // ... }
  34. 81.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextSt ↳ DefaultTextStyle ↳ _CardContentsPl // flutter/packages/flutter/lib/src/material/material.dart /// The interior of non-transparent material. /// /// Animates [elevation], [shadowColor], and [shape]. class _MaterialInterior extends ImplicitlyAnimatedWidget { // ... extends StatefulWidget }
  35. 82.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextSt ↳ DefaultTextStyle ↳ _CardContentsPl // flutter/packages/flutter/lib/src/material/material.dart /// The interior of non-transparent material. /// /// Animates [elevation], [shadowColor], and [shape]. class _MaterialInterior extends ImplicitlyAnimatedWidget { // ... extends StatefulWidget }
  36. 83.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextSt ↳ DefaultTextStyle ↳ _CardContentsPl // flutter/packages/flutter/lib/src/material/material.dart /// The interior of non-transparent material. /// /// Animates [elevation], [shadowColor], and [shape]. class _MaterialInterior extends ImplicitlyAnimatedWidget { // ... @override _MaterialInteriorState createState() => _MaterialInteriorState(); extends StatefulWidget }
  37. 84.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextSt ↳ DefaultTextStyle ↳ _CardContentsPl // flutter/packages/flutter/lib/src/material/material.dart /// The interior of non-transparent material. /// /// Animates [elevation], [shadowColor], and [shape]. class _MaterialInterior extends ImplicitlyAnimatedWidget { // ... @override _MaterialInteriorState createState() => _MaterialInteriorState(); }
  38. 85.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultText ↳ DefaultTextStyle ↳ _CardContents // flutter/packages/flutter/lib/src/material/material.dart /// The interior of non-transparent material. /// /// Animates [elevation], [shadowColor], and [shape]. class _MaterialInterior extends ImplicitlyAnimatedWidget { // ... @override _MaterialInteriorState createState() => _MaterialInteriorState(); }
  39. 86.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTe ↳ DefaultTextSty ↳ _CardConten // flutter/packages/flutter/lib/src/material/material.dart /// The interior of non-transparent material. /// /// Animates [elevation], [shadowColor], and [shape]. class _MaterialInterior extends ImplicitlyAnimatedWidget { // ... @override _MaterialInteriorState createState() => _MaterialInteriorState(); }
  40. 87.

    t { ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox

    ↳ Card ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle ↳ DefaultTextStyle ↳ _CardContentsPlaceholder↳
  41. 88.

    t { ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox

    ↳ Card ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle ↳ DefaultTextStyle ↳ _CardContentsPlaceholder↳
  42. 89.

    t { ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox

    ↳ Card ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle↳ ↳ DefaultTextStyle ↳ _CardContentsPlaceholder↳
  43. 90.

    t { ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox

    ↳ Card ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle↳ ↳ DefaultTextStyle
  44. 91.

    t { ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox

    ↳ Card ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle↳ ↳ DefaultTextStyle
  45. 93.

    t { ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox

    ↳ Card ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle↳ ↳ DefaultTextStyle
  46. 94.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul // flutter/packages/flutter/lib/src/widgets/framework.dart @immutable abstract class Widget extends DiagnosticableTree { // ... @protected Element createElement(); // ... }
  47. 95.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul // flutter/packages/flutter/lib/src/widgets/framework.dart abstract class Element extends DiagnosticableTree implements BuildContext { // ... }
  48. 96.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul void main() => runApp(MyApp()); class MyApp extends StatelessWidget { static const _buttonText = Text("Let there be Snackbar..."); static const _snackbarText = Text("...and there was Snackbar"); static const _snackbar = SnackBar(content: _snackbarText); @override Widget build(context) => MaterialApp( home: Scaffold( body: Center( child: RaisedButton( child: _buttonText, onPressed: () => Scaffold.of(context) .showSnackBar(_snackbar), ), ), ), ); }
  49. 97.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul void main() => runApp(MyApp()); class MyApp extends StatelessWidget { static const _buttonText = Text("Let there be Snackbar..."); static const _snackbarText = Text("...and there was Snackbar"); static const _snackbar = SnackBar(content: _snackbarText); @override Widget build(context) => MaterialApp( home: Scaffold( body: Center( child: Builder( builder: (context) => RaisedButton( child: _buttonText, onPressed: () => Scaffold.of(context).showSnackBar(_snackbar), ), ), ), ), ); }
  50. 98.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul void main() => runApp(MyApp()); class MyApp extends StatelessWidget { static const _buttonText = Text("Let there be Snackbar..."); static const _snackbarText = Text("...and there was Snackbar"); static const _snackbar = SnackBar(content: _snackbarText); @override Widget build(context) => MaterialApp( home: Scaffold( body: Center( child: Builder( builder: (context) => RaisedButton( child: _buttonText, onPressed: () => Scaffold.of(context).showSnackBar(_snackbar), ), ), ), ), ); }
  51. 99.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul // flutter/packages/flutter/lib/src/widgets/framework.dart abstract class Element extends DiagnosticableTree implements BuildContext { // ... }
  52. 100.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul // flutter/packages/flutter/lib/src/widgets/framework.dart abstract class Element extends DiagnosticableTree implements BuildContext { // ... RenderObject get renderObject { // ... } // ... }
  53. 102.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul // flutter/packages/flutter/lib/src/rendering/object.dart abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget { // ... }
  54. 103.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationLis ↳ _InkFeatures ↳ AnimatedD ↳ Defaul // flutter/packages/flutter/lib/src/widgets/basic.dart /// Creates a physical model with an arbitrary shape clip. class PhysicalShape extends SingleChildRenderObjectWidget { // ... @override RenderPhysicalShape createRenderObject(BuildContext context) => RenderPhysicalShape( clipper: clipper, elevation: elevation, color: color, shadowColor: shadowColor, ); @override void updateRenderObject( BuildContext context, RenderPhysicalShape renderObject) { renderObject ..clipper = clipper ..elevation = elevation ..color = color ..shadowColor = shadowColor; } }
  55. 104.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle↳ ↳ DefaultTextStyle
  56. 105.

    ↳ Container ↳ DecoratedBox ↳ Align ↳ SizedBox ↳ Card

    ↳ Semantics ↳ Container ↳ Padding ↳ Material ↳ _MaterialInterior ↳ PhysicalShape ↳ _ShapeBorderPaint ↳ CustomPaint ↳ NotificationListener ↳ _InkFeatures ↳ AnimatedDefaultTextStyle↳ ↳ DefaultTextStyle ↳ ↳ RenderDecoratedBox ↳ RenderPositionedBox ↳ RenderConstrainedBox ↳ ↳ RenderSemanticsAnnotations ↳ ↳ RenderPadding ↳ ↳ ↳ RenderPhysicalShape ↳ RenderCustomPaint ↳ ↳ ↳ _RenderInkFeatures↳
  57. 106.

    ↳ ↳ RenderDecoratedBox ↳ RenderPositionedBox ↳ RenderConstrainedBox ↳ ↳ RenderSemanticsAnnotations

    ↳ ↳ RenderPadding ↳ ↳ ↳ RenderPhysicalShape ↳ RenderCustomPaint ↳ ↳ ↳ _RenderInkFeatures↳
  58. 108.

    // flutter/packages/flutter/lib/src/rendering/proxy_box.dart class RenderPhysicalShape extends _RenderPhysicalModelBase<Path> { // ... @override

    void paint(PaintingContext context, Offset offset) { // ... if (elevation != 0.0) { canvas.drawShadow( offsetPath, shadowColor, elevation, color.alpha != 0xFF, ); } // ... } // ... }
  59. 110.

    // flutter/bin/cache/pkg/sky_engine/lib/ui/painting.dart class Canvas extends NativeFieldWrapperClass2 { // ... ///

    Draws a shadow for a [Path] representing the given /// material elevation. void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { assert(path != null); assert(color != null); assert(transparentOccluder != null); _drawShadow(path, color.value, elevation, transparentOccluder); } void _drawShadow(Path path, int color, double elevation, bool transparentOccluder) native 'Canvas_drawShadow'; }
  60. 112.

    // engine/lib/ui/painting/canvas.cc namespace blink { // ... void Canvas::drawShadow(const CanvasPath*

    path, SkColor color, double elevation, bool transparentOccluder) { SkScalar dpr = UIDartState::Current()->window()-> viewport_metrics().device_pixel_ratio; flow::PhysicalShapeLayer::DrawShadow( canvas_, path->path(), color, elevation, transparentOccluder, dpr ); } // ... }
  61. 113.

    // engine/flow/layers/physical_shape_layer.cc #include "third_party/skia/include/utils/SkShadowUtils.h" namespace flow { //... void PhysicalShapeLayer::DrawShadow(

    SkCanvas* canvas, const SkPath& path, SkColor color, float elevation, bool transparentOccluder, SkScalar dpr ) { // ... SkShadowFlags flags = // ... const SkRect& bounds = path.getBounds(); SkScalar shadow_x = (bounds.left() + bounds.right()) / 2; SkScalar shadow_y = bounds.top() - 600.0f; SkColor inAmbient = SkColorSetA(color, kAmbientAlpha * SkColorGetA(color)); SkColor inSpot = SkColorSetA(color, kSpotAlpha * SkColorGetA(color)); SkColor ambientColor, spotColor; SkShadowUtils::ComputeTonalColors(inAmbient, inSpot, &ambientColor, &spotColor); SkShadowUtils::DrawShadow(canvas, path, SkPoint3::Make(0, 0, dpr * elevation), SkPoint3::Make(shadow_x, shadow_y, dpr * kLightHeight), dpr * kLightRadius, ambientColor, spotColor, flags); } // ... }
  62. 115.
  63. 117.

    Links Widgets, Elements, and RenderObjects: 
 “The Mahogany Staircase -

    Flutter's Layered Design” (by Ian Hickson) — youtu.be/dkyY9WCGMi0 Best Flutter Introduction: “A New Hope” (by us!) — bit.ly/a-new-hope-flutter Flutter Threads: “Flutter Performance Profiling” — flutter.io/ui-performance Flutter Framework Sources — github.com/flutter/flutter Flutter Engine Sources — github.com/flutter/engine Skia Sources — github.com/google/skia
  64. 118.

    Acknowledgements “Arvo” font — by Anton Koovit, licensed under SIL

    1.1 “Kreon” font — by Julia Petretta, licensed under SIL 1.1 “League Mono” font — by The League of Moveable Type, licensed under SIL 1.1 “Matteugenio” drawings — by Sio (@scottecs) Golden dividers collection — Designed by Raftel/Freepik