This reverts commit 803b15e0db.
This commit is contained in:
@@ -1580,8 +1580,12 @@ abstract class _RenderPhysicalModelBase<T> extends _RenderCustomClip<T> {
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
static final Paint _transparentPaint = Paint()..color = const Color(0x00000000);
|
||||
|
||||
// On Fuchsia, the system compositor is responsible for drawing shadows
|
||||
// for physical model layers with non-zero elevation.
|
||||
@override
|
||||
bool get alwaysNeedsCompositing => _elevation != 0.0;
|
||||
bool get alwaysNeedsCompositing => _elevation != 0.0 && defaultTargetPlatform == TargetPlatform.fuchsia;
|
||||
|
||||
@override
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
@@ -1711,14 +1715,37 @@ class RenderPhysicalModel extends _RenderPhysicalModelBase<RRect> {
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
final PhysicalModelLayer physicalModel = PhysicalModelLayer(
|
||||
clipPath: offsetRRectAsPath,
|
||||
clipBehavior: clipBehavior,
|
||||
elevation: paintShadows ? elevation : 0.0,
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
);
|
||||
context.pushLayer(physicalModel, super.paint, offset, childPaintBounds: offsetBounds);
|
||||
if (needsCompositing) {
|
||||
final PhysicalModelLayer physicalModel = PhysicalModelLayer(
|
||||
clipPath: offsetRRectAsPath,
|
||||
clipBehavior: clipBehavior,
|
||||
elevation: paintShadows ? elevation : 0.0,
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
);
|
||||
context.pushLayer(physicalModel, super.paint, offset, childPaintBounds: offsetBounds);
|
||||
} else {
|
||||
final Canvas canvas = context.canvas;
|
||||
if (elevation != 0.0 && paintShadows) {
|
||||
// The drawShadow call doesn't add the region of the shadow to the
|
||||
// picture's bounds, so we draw a hardcoded amount of extra space to
|
||||
// account for the maximum potential area of the shadow.
|
||||
// TODO(jsimmons): remove this when Skia does it for us.
|
||||
canvas.drawRect(
|
||||
offsetBounds.inflate(20.0),
|
||||
_RenderPhysicalModelBase._transparentPaint,
|
||||
);
|
||||
canvas.drawShadow(
|
||||
offsetRRectAsPath,
|
||||
shadowColor,
|
||||
elevation,
|
||||
color.alpha != 0xFF,
|
||||
);
|
||||
}
|
||||
canvas.drawRRect(offsetRRect, Paint()..color = color);
|
||||
context.clipRRectAndPaint(offsetRRect, clipBehavior, offsetBounds, () => super.paint(context, offset));
|
||||
assert(context.canvas == canvas, 'canvas changed even though needsCompositing was false');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1801,14 +1828,37 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase<Path> {
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
final PhysicalModelLayer physicalModel = PhysicalModelLayer(
|
||||
clipPath: offsetPath,
|
||||
clipBehavior: clipBehavior,
|
||||
elevation: paintShadows ? elevation : 0.0,
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
);
|
||||
context.pushLayer(physicalModel, super.paint, offset, childPaintBounds: offsetBounds);
|
||||
if (needsCompositing) {
|
||||
final PhysicalModelLayer physicalModel = PhysicalModelLayer(
|
||||
clipPath: offsetPath,
|
||||
clipBehavior: clipBehavior,
|
||||
elevation: paintShadows ? elevation : 0.0,
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
);
|
||||
context.pushLayer(physicalModel, super.paint, offset, childPaintBounds: offsetBounds);
|
||||
} else {
|
||||
final Canvas canvas = context.canvas;
|
||||
if (elevation != 0.0 && paintShadows) {
|
||||
// The drawShadow call doesn't add the region of the shadow to the
|
||||
// picture's bounds, so we draw a hardcoded amount of extra space to
|
||||
// account for the maximum potential area of the shadow.
|
||||
// TODO(jsimmons): remove this when Skia does it for us.
|
||||
canvas.drawRect(
|
||||
offsetBounds.inflate(20.0),
|
||||
_RenderPhysicalModelBase._transparentPaint,
|
||||
);
|
||||
canvas.drawShadow(
|
||||
offsetPath,
|
||||
shadowColor,
|
||||
elevation,
|
||||
color.alpha != 0xFF,
|
||||
);
|
||||
}
|
||||
canvas.drawPath(offsetPath, Paint()..color = color..style = PaintingStyle.fill);
|
||||
context.clipPathAndPaint(offsetPath, clipBehavior, offsetBounds, () => super.paint(context, offset));
|
||||
assert(context.canvas == canvas, 'canvas changed even though needsCompositing was false');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@@ -81,7 +79,7 @@ void main() {
|
||||
find.byKey(key),
|
||||
matchesGoldenFile('bottom_app_bar.custom_shape.2.png'),
|
||||
);
|
||||
}, skip: !Platform.isLinux);
|
||||
});
|
||||
|
||||
testWidgets('color defaults to Theme.bottomAppBarColor', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
|
||||
@@ -10,27 +10,6 @@ import '../rendering/mock_canvas.dart';
|
||||
import '../widgets/semantics_tester.dart';
|
||||
|
||||
void main() {
|
||||
PhysicalModelLayer findPhysicalLayer(Element element) {
|
||||
expect(element, isNotNull);
|
||||
RenderObject object = element.renderObject;
|
||||
while (object != null && object is! RenderRepaintBoundary && object is! RenderView) {
|
||||
object = object.parent;
|
||||
}
|
||||
expect(object.debugLayer, isNotNull);
|
||||
expect(object.debugLayer.firstChild, isInstanceOf<PhysicalModelLayer>());
|
||||
final PhysicalModelLayer layer = object.debugLayer.firstChild;
|
||||
return layer.firstChild is PhysicalModelLayer ? layer.firstChild : layer;
|
||||
}
|
||||
|
||||
void checkPhysicalLayer(Element element, Color expectedColor, {Path clipPath, Rect clipRect}) {
|
||||
final PhysicalModelLayer expectedLayer = findPhysicalLayer(element);
|
||||
expect(expectedLayer.elevation, 0.0);
|
||||
expect(expectedLayer.color, expectedColor);
|
||||
if (clipPath != null) {
|
||||
expect(clipRect, isNotNull);
|
||||
expect(expectedLayer.clipPath, coversSameAreaAs(clipPath, areaToCompare: clipRect.inflate(10.0)));
|
||||
}
|
||||
}
|
||||
testWidgets('Outline button responds to tap when enabled', (WidgetTester tester) async {
|
||||
int pressedCount = 0;
|
||||
|
||||
@@ -135,13 +114,8 @@ void main() {
|
||||
expect(
|
||||
outlineButton,
|
||||
paints
|
||||
..clipPath(pathMatcher: coversSameAreaAs(clipPath, areaToCompare: clipRect.inflate(10.0)))
|
||||
..path(color: disabledBorderColor, strokeWidth: borderWidth));
|
||||
checkPhysicalLayer(
|
||||
tester.element(outlineButton),
|
||||
const Color(0),
|
||||
clipPath: clipPath,
|
||||
clipRect: clipRect,
|
||||
);
|
||||
|
||||
// Pump a new button with a no-op onPressed callback to make it enabled.
|
||||
await tester.pumpWidget(
|
||||
@@ -156,14 +130,10 @@ void main() {
|
||||
expect(
|
||||
outlineButton,
|
||||
paints
|
||||
// initially the interior of the button is transparent
|
||||
..path(color: fillColor.withAlpha(0x00))
|
||||
..clipPath(pathMatcher: coversSameAreaAs(clipPath, areaToCompare: clipRect.inflate(10.0)))
|
||||
..path(color: borderColor, strokeWidth: borderWidth));
|
||||
// initially, the interior of the button is transparent
|
||||
checkPhysicalLayer(
|
||||
tester.element(outlineButton),
|
||||
fillColor.withAlpha(0x00),
|
||||
clipPath: clipPath,
|
||||
clipRect: clipRect,
|
||||
);
|
||||
|
||||
final Offset center = tester.getCenter(outlineButton);
|
||||
final TestGesture gesture = await tester.startGesture(center);
|
||||
@@ -174,13 +144,9 @@ void main() {
|
||||
expect(
|
||||
outlineButton,
|
||||
paints
|
||||
..path(color: fillColor.withAlpha(0xFF))
|
||||
..clipPath(pathMatcher: coversSameAreaAs(clipPath, areaToCompare: clipRect.inflate(10.0)))
|
||||
..path(color: highlightedBorderColor, strokeWidth: borderWidth));
|
||||
checkPhysicalLayer(
|
||||
tester.element(outlineButton),
|
||||
fillColor.withAlpha(0xFF),
|
||||
clipPath: clipPath,
|
||||
clipRect: clipRect,
|
||||
);
|
||||
|
||||
// Tap gesture completes, button returns to its initial configuration.
|
||||
await gesture.up();
|
||||
@@ -188,13 +154,9 @@ void main() {
|
||||
expect(
|
||||
outlineButton,
|
||||
paints
|
||||
..path(color: fillColor.withAlpha(0x00))
|
||||
..clipPath(pathMatcher: coversSameAreaAs(clipPath, areaToCompare: clipRect.inflate(10.0)))
|
||||
..path(color: borderColor, strokeWidth: borderWidth));
|
||||
checkPhysicalLayer(
|
||||
tester.element(outlineButton),
|
||||
fillColor.withAlpha(0x00),
|
||||
clipPath: clipPath,
|
||||
clipRect: clipRect,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('OutlineButton has no clip by default', (WidgetTester tester) async {
|
||||
@@ -260,6 +222,7 @@ void main() {
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
|
||||
testWidgets('OutlineButton scales textScaleFactor', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
@@ -377,7 +340,6 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(buildFrame(ThemeData.dark()));
|
||||
final Finder button = find.byType(OutlineButton);
|
||||
final Element buttonElement = tester.element(button);
|
||||
final Offset center = tester.getCenter(button);
|
||||
|
||||
// Default value for dark Theme.of(context).canvasColor as well as
|
||||
@@ -385,18 +347,18 @@ void main() {
|
||||
Color fillColor = Colors.grey[850];
|
||||
|
||||
// Initially the interior of the button is transparent.
|
||||
checkPhysicalLayer(buttonElement, fillColor.withAlpha(0x00));
|
||||
expect(button, paints..path(color: fillColor.withAlpha(0x00)));
|
||||
|
||||
// Tap-press gesture on the button triggers the fill animation.
|
||||
TestGesture gesture = await tester.startGesture(center);
|
||||
await tester.pump(); // Start the button fill animation.
|
||||
await tester.pump(const Duration(milliseconds: 200)); // Animation is complete.
|
||||
checkPhysicalLayer(buttonElement, fillColor.withAlpha(0xFF));
|
||||
expect(button, paints..path(color: fillColor.withAlpha(0xFF)));
|
||||
|
||||
// Tap gesture completes, button returns to its initial configuration.
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
checkPhysicalLayer(buttonElement, fillColor.withAlpha(0x00));
|
||||
expect(button, paints..path(color: fillColor.withAlpha(0x00)));
|
||||
|
||||
await tester.pumpWidget(buildFrame(ThemeData.light()));
|
||||
await tester.pumpAndSettle(); // Finish the theme change animation.
|
||||
@@ -406,17 +368,17 @@ void main() {
|
||||
fillColor = Colors.grey[50];
|
||||
|
||||
// Initially the interior of the button is transparent.
|
||||
// expect(button, paints..path(color: fillColor.withAlpha(0x00)));
|
||||
expect(button, paints..path(color: fillColor.withAlpha(0x00)));
|
||||
|
||||
// Tap-press gesture on the button triggers the fill animation.
|
||||
gesture = await tester.startGesture(center);
|
||||
await tester.pump(); // Start the button fill animation.
|
||||
await tester.pump(const Duration(milliseconds: 200)); // Animation is complete.
|
||||
checkPhysicalLayer(buttonElement, fillColor.withAlpha(0xFF));
|
||||
expect(button, paints..path(color: fillColor.withAlpha(0xFF)));
|
||||
|
||||
// Tap gesture completes, button returns to its initial configuration.
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
checkPhysicalLayer(buttonElement, fillColor.withAlpha(0x00));
|
||||
expect(button, paints..path(color: fillColor.withAlpha(0x00)));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -64,10 +64,10 @@ void main() {
|
||||
layout(root, phase: EnginePhase.composite);
|
||||
expect(root.needsCompositing, isFalse);
|
||||
|
||||
// Flutter now composites physical shapes on all platforms.
|
||||
// On non-Fuchsia platforms, Flutter draws its own shadows.
|
||||
root.elevation = 1.0;
|
||||
pumpFrame(phase: EnginePhase.composite);
|
||||
expect(root.needsCompositing, isTrue);
|
||||
expect(root.needsCompositing, isFalse);
|
||||
|
||||
root.elevation = 0.0;
|
||||
pumpFrame(phase: EnginePhase.composite);
|
||||
@@ -127,10 +127,10 @@ void main() {
|
||||
layout(root, phase: EnginePhase.composite);
|
||||
expect(root.needsCompositing, isFalse);
|
||||
|
||||
// On non-Fuchsia platforms, we composite physical shape layers
|
||||
// On non-Fuchsia platforms, Flutter draws its own shadows.
|
||||
root.elevation = 1.0;
|
||||
pumpFrame(phase: EnginePhase.composite);
|
||||
expect(root.needsCompositing, isTrue);
|
||||
expect(root.needsCompositing, isFalse);
|
||||
|
||||
root.elevation = 0.0;
|
||||
pumpFrame(phase: EnginePhase.composite);
|
||||
|
||||
@@ -6,7 +6,8 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/gestures.dart' show DragStartBehavior;
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
import '../rendering/mock_canvas.dart';
|
||||
|
||||
class _CustomPhysics extends ClampingScrollPhysics {
|
||||
const _CustomPhysics({ ScrollPhysics parent }) : super(parent: parent);
|
||||
@@ -468,38 +469,12 @@ void main() {
|
||||
// END
|
||||
)),
|
||||
);
|
||||
|
||||
PhysicalModelLayer _dfsFindPhysicalLayer(ContainerLayer layer) {
|
||||
expect(layer, isNotNull);
|
||||
Layer child = layer.firstChild;
|
||||
while (child != null) {
|
||||
if (child is PhysicalModelLayer) {
|
||||
return child;
|
||||
}
|
||||
if (child is ContainerLayer) {
|
||||
final PhysicalModelLayer candidate = _dfsFindPhysicalLayer(child);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
child = child.nextSibling;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final ContainerLayer nestedScrollViewLayer = find.byType(NestedScrollView).evaluate().first.renderObject.debugLayer;
|
||||
void _checkPhysicalLayer({@required double elevation}) {
|
||||
final PhysicalModelLayer layer = _dfsFindPhysicalLayer(nestedScrollViewLayer);
|
||||
expect(layer, isNotNull);
|
||||
expect(layer.elevation, equals(elevation));
|
||||
}
|
||||
|
||||
int expectedBuildCount = 0;
|
||||
expectedBuildCount += 1;
|
||||
expect(buildCount, expectedBuildCount);
|
||||
expect(find.text('Item 2'), findsOneWidget);
|
||||
expect(find.text('Item 18'), findsNothing);
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
// scroll down
|
||||
final TestGesture gesture0 = await tester.startGesture(tester.getCenter(find.text('Item 2')));
|
||||
await gesture0.moveBy(const Offset(0.0, -120.0)); // tiny bit more than the pinned app bar height (56px * 2)
|
||||
@@ -513,22 +488,22 @@ void main() {
|
||||
expect(buildCount, expectedBuildCount);
|
||||
await tester.pump(const Duration(milliseconds: 1)); // during shadow animation
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 0.00018262863159179688);
|
||||
expect(find.byType(NestedScrollView), paints..shadow());
|
||||
await tester.pump(const Duration(seconds: 1)); // end shadow animation
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 4);
|
||||
expect(find.byType(NestedScrollView), paints..shadow());
|
||||
// scroll down
|
||||
final TestGesture gesture1 = await tester.startGesture(tester.getCenter(find.text('Item 2')));
|
||||
await gesture1.moveBy(const Offset(0.0, -800.0));
|
||||
await tester.pump();
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 4);
|
||||
expect(find.byType(NestedScrollView), paints..shadow());
|
||||
expect(find.text('Item 2'), findsNothing);
|
||||
expect(find.text('Item 18'), findsOneWidget);
|
||||
await gesture1.up();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 4);
|
||||
expect(find.byType(NestedScrollView), paints..shadow());
|
||||
// swipe left to bring in tap on the right
|
||||
final TestGesture gesture2 = await tester.startGesture(tester.getCenter(find.byType(NestedScrollView)));
|
||||
await gesture2.moveBy(const Offset(-400.0, 0.0));
|
||||
@@ -539,7 +514,7 @@ void main() {
|
||||
expect(find.text('Item 0'), findsOneWidget);
|
||||
expect(tester.getTopLeft(find.ancestor(of: find.text('Item 0'), matching: find.byType(ListTile))).dy,
|
||||
tester.getBottomLeft(find.byType(AppBar)).dy + 8.0);
|
||||
_checkPhysicalLayer(elevation: 4);
|
||||
expect(find.byType(NestedScrollView), paints..shadow());
|
||||
await gesture2.up();
|
||||
await tester.pump(); // start sideways scroll
|
||||
await tester.pump(const Duration(seconds: 1)); // end sideways scroll, triggers shadow going away
|
||||
@@ -551,7 +526,7 @@ void main() {
|
||||
expect(buildCount, expectedBuildCount);
|
||||
expect(find.text('Item 18'), findsNothing);
|
||||
expect(find.text('Item 2'), findsOneWidget);
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
await tester.pump(const Duration(seconds: 1)); // just checking we don't rebuild...
|
||||
expect(buildCount, expectedBuildCount);
|
||||
// peek left to see it's still in the right place
|
||||
@@ -564,10 +539,10 @@ void main() {
|
||||
expect(buildCount, expectedBuildCount);
|
||||
expect(find.text('Item 18'), findsOneWidget);
|
||||
expect(find.text('Item 2'), findsOneWidget);
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
await tester.pump(const Duration(seconds: 1)); // shadow finishes coming back
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 4);
|
||||
expect(find.byType(NestedScrollView), paints..shadow());
|
||||
await gesture3.moveBy(const Offset(-400.0, 0.0));
|
||||
await gesture3.up();
|
||||
await tester.pump(); // left tab view goes away
|
||||
@@ -575,10 +550,10 @@ void main() {
|
||||
await tester.pump(); // shadow goes away starting here
|
||||
expectedBuildCount += 1;
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 4);
|
||||
expect(find.byType(NestedScrollView), paints..shadow());
|
||||
await tester.pump(const Duration(seconds: 1)); // shadow finishes going away
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
// scroll back up
|
||||
final TestGesture gesture4 = await tester.startGesture(tester.getCenter(find.byType(NestedScrollView)));
|
||||
await gesture4.moveBy(const Offset(0.0, 200.0)); // expands the appbar again
|
||||
@@ -586,11 +561,11 @@ void main() {
|
||||
expect(buildCount, expectedBuildCount);
|
||||
expect(find.text('Item 2'), findsOneWidget);
|
||||
expect(find.text('Item 18'), findsNothing);
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
await gesture4.up();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
// peek left to see it's now back at zero
|
||||
final TestGesture gesture5 = await tester.startGesture(tester.getCenter(find.byType(NestedScrollView)));
|
||||
await gesture5.moveBy(const Offset(400.0, 0.0));
|
||||
@@ -599,14 +574,14 @@ void main() {
|
||||
expect(buildCount, expectedBuildCount);
|
||||
expect(find.text('Item 18'), findsNothing);
|
||||
expect(find.text('Item 2'), findsNWidgets(2));
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
await tester.pump(const Duration(seconds: 1)); // shadow would be finished coming back
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
await gesture5.up();
|
||||
await tester.pump(); // right tab view goes away
|
||||
await tester.pumpAndSettle();
|
||||
expect(buildCount, expectedBuildCount);
|
||||
_checkPhysicalLayer(elevation: 0);
|
||||
expect(find.byType(NestedScrollView), isNot(paints..shadow()));
|
||||
debugDisableShadows = true;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user