From 8aa43149306e59dd351697f8200d4dd8560c929e Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Mon, 20 Mar 2017 16:00:47 -0700 Subject: [PATCH] Render Material using a PhysicalModel with optional compositing (#8920) --- .../flutter/lib/src/material/material.dart | 31 +++++++++++---- .../flutter/lib/src/rendering/object.dart | 38 +++++++++++++------ .../flutter/lib/src/rendering/proxy_box.dart | 5 +-- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart index 0fa3ddca51..91bdaf1b4d 100644 --- a/packages/flutter/lib/src/material/material.dart +++ b/packages/flutter/lib/src/material/material.dart @@ -7,7 +7,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'constants.dart'; -import 'shadows.dart'; import 'theme.dart'; /// Signature for the callback used by ink effects to obtain the rectangle for the effect. @@ -228,14 +227,33 @@ class _MaterialState extends State with TickerProviderStateMixin { vsync: this, ) ); + if (config.type == MaterialType.circle) { - contents = new ClipOval(child: contents); - } else if (kMaterialEdges[config.type] != null) { - contents = new ClipRRect( - borderRadius: radius, - child: contents + contents = new PhysicalModel( + shape: BoxShape.circle, + elevation: config.elevation, + color: backgroundColor, + child: contents, + ); + } else if (config.type == MaterialType.transparency) { + if (radius == null) { + contents = new ClipRect(child: contents); + } else { + contents = new ClipRRect( + borderRadius: radius, + child: contents + ); + } + } else { + contents = new PhysicalModel( + shape: BoxShape.rectangle, + borderRadius: radius ?? BorderRadius.zero, + elevation: config.elevation, + color: backgroundColor, + child: contents, ); } + if (config.type != MaterialType.transparency) { contents = new AnimatedContainer( curve: Curves.fastOutSlowIn, @@ -247,7 +265,6 @@ class _MaterialState extends State with TickerProviderStateMixin { child: new Container( decoration: new BoxDecoration( borderRadius: radius, - boxShadow: config.elevation == 0 ? null : kElevationToShadow[config.elevation], backgroundColor: backgroundColor, shape: config.type == MaterialType.circle ? BoxShape.circle : BoxShape.rectangle ), diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 5e2a22d77e..47d3ebaea5 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -442,19 +442,35 @@ class PaintingContext { /// * `color` is the background color. /// * `painter` is a callback that will paint with the `clipRRect` applied. This /// function calls the `painter` synchronously. - void pushPhysicalModel(Offset offset, Rect bounds, RRect clipRRect, int elevation, Color color, PaintingContextCallback painter) { + void pushPhysicalModel(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, int elevation, Color color, PaintingContextCallback painter) { final Rect offsetBounds = bounds.shift(offset); final RRect offsetClipRRect = clipRRect.shift(offset); - _stopRecordingIfNeeded(); - final PhysicalModelLayer physicalModel = new PhysicalModelLayer( - clipRRect: offsetClipRRect, - elevation: elevation, - color: color, - ); - _appendLayer(physicalModel); - final PaintingContext childContext = new PaintingContext._(physicalModel, offsetBounds); - painter(childContext, offset); - childContext._stopRecordingIfNeeded(); + if (needsCompositing) { + _stopRecordingIfNeeded(); + final PhysicalModelLayer physicalModel = new PhysicalModelLayer( + clipRRect: offsetClipRRect, + elevation: elevation, + color: color, + ); + _appendLayer(physicalModel); + final PaintingContext childContext = new PaintingContext._(physicalModel, offsetBounds); + painter(childContext, offset); + childContext._stopRecordingIfNeeded(); + } else { + if (elevation != 0) { + canvas.drawShadow( + new Path()..addRRect(offsetClipRRect), + const Color(0xFF000000), + elevation, + color.alpha != 0xFF, + ); + } + canvas.drawRRect(offsetClipRRect, new Paint()..color=color); + canvas.saveLayer(offsetBounds, _defaultPaint); + canvas.clipRRect(offsetClipRRect); + painter(this, offset); + canvas.restore(); + } } } diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index aaacd1613e..bd57fc5fb8 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -1210,9 +1210,6 @@ class RenderPhysicalModel extends _RenderCustomClip { assert(_borderRadius != null); } - @override - bool get alwaysNeedsCompositing => true; - /// The shape of the layer. BoxShape get shape => _shape; BoxShape _shape; @@ -1285,7 +1282,7 @@ class RenderPhysicalModel extends _RenderCustomClip { void paint(PaintingContext context, Offset offset) { if (child != null) { _updateClip(); - context.pushPhysicalModel(offset, _clip.outerRect, _clip, _elevation, _color, super.paint); + context.pushPhysicalModel(needsCompositing, offset, _clip.outerRect, _clip, _elevation, _color, super.paint); } } }