Support clipBehavior changes in hot reload (#31761)

## Description

Make `_RenderCustomClip`'s `clipBehavior` non-final so we can update it during `updateRenderObject`. This will support `clipBehavior` changes in hot reload.

## Related Issues

Fixes #30863

## Tests

I added the following tests:

* ClipRect updates clipBehavior in updateRenderObject
* ClipRRect updates clipBehavior in updateRenderObject
* ClipOval updates clipBehavior in updateRenderObject
* ClipPath updates clipBehavior in updateRenderObject
* PhysicalModel updates clipBehavior in updateRenderObject
* PhysicalShape updates clipBehavior in updateRenderObject
This commit is contained in:
liyuqian 2019-04-30 09:46:38 -07:00 committed by GitHub
parent eae67f05df
commit 7cab6d5e1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 7 deletions

View file

@ -1463,6 +1463,7 @@ class PhysicalModelLayer extends ContainerLayer {
Clip get clipBehavior => _clipBehavior;
Clip _clipBehavior;
set clipBehavior(Clip value) {
assert(value != null);
if (value != _clipBehavior) {
_clipBehavior = value;
markNeedsAddToScene();

View file

@ -1152,9 +1152,10 @@ abstract class _RenderCustomClip<T> extends RenderProxyBox {
_RenderCustomClip({
RenderBox child,
CustomClipper<T> clipper,
this.clipBehavior = Clip.antiAlias,
}) : _clipper = clipper,
assert(clipBehavior != null),
Clip clipBehavior = Clip.antiAlias,
}) : assert(clipBehavior != null),
_clipper = clipper,
_clipBehavior = clipBehavior,
super(child);
/// If non-null, determines which clip to use on the child.
@ -1198,7 +1199,14 @@ abstract class _RenderCustomClip<T> extends RenderProxyBox {
T get _defaultClip;
T _clip;
final Clip clipBehavior;
Clip get clipBehavior => _clipBehavior;
set clipBehavior(Clip value) {
if (value != _clipBehavior) {
_clipBehavior = value;
markNeedsPaint();
}
}
Clip _clipBehavior;
@override
void performLayout() {

View file

@ -594,7 +594,9 @@ class ClipRect extends SingleChildRenderObjectWidget {
@override
void updateRenderObject(BuildContext context, RenderClipRect renderObject) {
renderObject.clipper = clipper;
renderObject
..clipper = clipper
..clipBehavior = clipBehavior;
}
@override
@ -661,6 +663,7 @@ class ClipRRect extends SingleChildRenderObjectWidget {
void updateRenderObject(BuildContext context, RenderClipRRect renderObject) {
renderObject
..borderRadius = borderRadius
..clipBehavior = clipBehavior
..clipper = clipper;
}
@ -710,7 +713,9 @@ class ClipOval extends SingleChildRenderObjectWidget {
@override
void updateRenderObject(BuildContext context, RenderClipOval renderObject) {
renderObject.clipper = clipper;
renderObject
..clipper = clipper
..clipBehavior = clipBehavior;
}
@override
@ -796,7 +801,9 @@ class ClipPath extends SingleChildRenderObjectWidget {
@override
void updateRenderObject(BuildContext context, RenderClipPath renderObject) {
renderObject.clipper = clipper;
renderObject
..clipper = clipper
..clipBehavior = clipBehavior;
}
@override
@ -886,6 +893,7 @@ class PhysicalModel extends SingleChildRenderObjectWidget {
void updateRenderObject(BuildContext context, RenderPhysicalModel renderObject) {
renderObject
..shape = shape
..clipBehavior = clipBehavior
..borderRadius = borderRadius
..elevation = elevation
..color = color
@ -974,6 +982,7 @@ class PhysicalShape extends SingleChildRenderObjectWidget {
void updateRenderObject(BuildContext context, RenderPhysicalShape renderObject) {
renderObject
..clipper = clipper
..clipBehavior = clipBehavior
..elevation = elevation
..color = color
..shadowColor = shadowColor;

View file

@ -40,7 +40,75 @@ class ValueClipper<T> extends CustomClipper<T> {
}
}
class _UpdateCountedClipRect extends ClipRect {
_UpdateCountedClipRect({Clip clipBehavior = Clip.antiAlias})
: super(clipBehavior: clipBehavior);
}
class _UpdateCountedClipRRect extends ClipRRect {
_UpdateCountedClipRRect({Clip clipBehavior = Clip.antiAlias})
: super(clipBehavior: clipBehavior, borderRadius: BorderRadius.circular(1.0));
}
class _UpdateCountedClipOval extends ClipOval {
_UpdateCountedClipOval({Clip clipBehavior = Clip.antiAlias})
: super(clipBehavior: clipBehavior);
}
class _UpdateCountedClipPath extends ClipPath {
_UpdateCountedClipPath({Clip clipBehavior = Clip.antiAlias})
: super(clipBehavior: clipBehavior);
}
void main() {
testWidgets('ClipRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
await tester.pumpWidget(_UpdateCountedClipRect());
final RenderClipRect renderClip = tester.allRenderObjects.whereType<RenderClipRect>().first;
expect(renderClip.clipBehavior, equals(Clip.antiAlias));
await tester.pumpWidget(_UpdateCountedClipRect(clipBehavior: Clip.hardEdge));
expect(renderClip.clipBehavior, equals(Clip.hardEdge));
});
testWidgets('ClipRRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
await tester.pumpWidget(_UpdateCountedClipRRect());
final RenderClipRRect renderClip = tester.allRenderObjects.whereType<RenderClipRRect>().first;
expect(renderClip.clipBehavior, equals(Clip.antiAlias));
await tester.pumpWidget(_UpdateCountedClipRRect(clipBehavior: Clip.hardEdge));
expect(renderClip.clipBehavior, equals(Clip.hardEdge));
});
testWidgets('ClipOval updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
await tester.pumpWidget(_UpdateCountedClipOval());
final RenderClipOval renderClip = tester.allRenderObjects.whereType<RenderClipOval>().first;
expect(renderClip.clipBehavior, equals(Clip.antiAlias));
await tester.pumpWidget(_UpdateCountedClipOval(clipBehavior: Clip.hardEdge));
expect(renderClip.clipBehavior, equals(Clip.hardEdge));
});
testWidgets('ClipPath updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
await tester.pumpWidget(_UpdateCountedClipPath());
final RenderClipPath renderClip = tester.allRenderObjects.whereType<RenderClipPath>().first;
expect(renderClip.clipBehavior, equals(Clip.antiAlias));
await tester.pumpWidget(_UpdateCountedClipPath(clipBehavior: Clip.hardEdge));
expect(renderClip.clipBehavior, equals(Clip.hardEdge));
});
testWidgets('ClipPath', (WidgetTester tester) async {
await tester.pumpWidget(
ClipPath(

View file

@ -10,7 +10,49 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
class _UpdateCountedPhysicalModel extends PhysicalModel {
_UpdateCountedPhysicalModel({Clip clipBehavior = Clip.none})
: super(clipBehavior: clipBehavior, color: Colors.red);
}
class _UpdateCountedPhysicalShape extends PhysicalShape {
_UpdateCountedPhysicalShape({Clip clipBehavior = Clip.none})
: super(clipBehavior: clipBehavior, color: Colors.red, clipper: ShapeBorderClipper(shape: CircleBorder()));
}
void main() {
testWidgets('PhysicalModel updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(home: _UpdateCountedPhysicalModel()),
);
final RenderPhysicalModel renderPhysicalModel = tester.allRenderObjects.whereType<RenderPhysicalModel>().first;
expect(renderPhysicalModel.clipBehavior, equals(Clip.none));
await tester.pumpWidget(
MaterialApp(home: _UpdateCountedPhysicalModel(clipBehavior: Clip.antiAlias)),
);
expect(renderPhysicalModel.clipBehavior, equals(Clip.antiAlias));
});
testWidgets('PhysicalShape updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(home: _UpdateCountedPhysicalShape()),
);
final RenderPhysicalShape renderPhysicalShape = tester.allRenderObjects.whereType<RenderPhysicalShape>().first;
expect(renderPhysicalShape.clipBehavior, equals(Clip.none));
await tester.pumpWidget(
MaterialApp(home: _UpdateCountedPhysicalShape(clipBehavior: Clip.antiAlias)),
);
expect(renderPhysicalShape.clipBehavior, equals(Clip.antiAlias));
});
testWidgets('PhysicalModel - creates a physical model layer when it needs compositing', (WidgetTester tester) async {
debugDisableShadows = false;
await tester.pumpWidget(