Add Clip enum to Material and related widgets (#18576)
See details in our proposal for this breaking API change and #18057. This PR setup all code paths to allow the change but doesn't change the clip behavior by itself. We'll change `defaultClipBehavior` from `Clip.antiAlias` to `Clip.none` in the following PR to change the clip behavior and update tests.
This commit is contained in:
parent
ad163749b7
commit
9ffa1c5174
@ -28,6 +28,7 @@ export 'src/painting/box_decoration.dart';
|
||||
export 'src/painting/box_fit.dart';
|
||||
export 'src/painting/box_shadow.dart';
|
||||
export 'src/painting/circle_border.dart';
|
||||
export 'src/painting/clip.dart';
|
||||
export 'src/painting/colors.dart';
|
||||
export 'src/painting/debug.dart';
|
||||
export 'src/painting/decoration.dart';
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show Clip, defaultClipBehavior; // ignore: deprecated_member_use
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -87,8 +89,9 @@ abstract class MaterialInkController {
|
||||
///
|
||||
/// The Material widget is responsible for:
|
||||
///
|
||||
/// 1. Clipping: Material clips its widget sub-tree to the shape specified by
|
||||
/// [shape], [type], and [borderRadius].
|
||||
/// 1. Clipping: If [clipBehavior] is not [Clip.none], Material clips its widget
|
||||
/// sub-tree to the shape specified by [shape], [type], and [borderRadius].
|
||||
/// By default, [clipBehavior] is [Clip.none] for performance considerations.
|
||||
/// 2. Elevation: Material elevates its widget sub-tree on the Z axis by
|
||||
/// [elevation] pixels, and draws the appropriate shadow.
|
||||
/// 3. Ink effects: Material shows ink effects implemented by [InkFeature]s
|
||||
@ -171,6 +174,7 @@ class Material extends StatefulWidget {
|
||||
this.textStyle,
|
||||
this.borderRadius,
|
||||
this.shape,
|
||||
this.clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
this.animationDuration = kThemeChangeDuration,
|
||||
this.child,
|
||||
}) : assert(type != null),
|
||||
@ -179,6 +183,7 @@ class Material extends StatefulWidget {
|
||||
assert(!(shape != null && borderRadius != null)),
|
||||
assert(animationDuration != null),
|
||||
assert(!(identical(type, MaterialType.circle) && (borderRadius != null || shape != null))),
|
||||
assert(clipBehavior != null),
|
||||
super(key: key);
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
@ -226,6 +231,14 @@ class Material extends StatefulWidget {
|
||||
/// zero.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// {@template flutter.widgets.Clip}
|
||||
/// The content will be clipped (or not) according to this option.
|
||||
///
|
||||
/// See the enum [Clip] for details of all possible options and their common
|
||||
/// use cases.
|
||||
/// {@endtemplate}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// Defines the duration of animated changes for [shape], [elevation],
|
||||
/// and [shadowColor].
|
||||
///
|
||||
@ -329,6 +342,7 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
|
||||
curve: Curves.fastOutSlowIn,
|
||||
duration: widget.animationDuration,
|
||||
shape: BoxShape.rectangle,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
borderRadius: BorderRadius.zero,
|
||||
elevation: widget.elevation,
|
||||
color: backgroundColor,
|
||||
@ -341,12 +355,13 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
|
||||
final ShapeBorder shape = _getShape();
|
||||
|
||||
if (widget.type == MaterialType.transparency)
|
||||
return _transparentInterior(shape: shape, contents: contents);
|
||||
return _transparentInterior(shape: shape, clipBehavior: widget.clipBehavior, contents: contents);
|
||||
|
||||
return new _MaterialInterior(
|
||||
curve: Curves.fastOutSlowIn,
|
||||
duration: widget.animationDuration,
|
||||
shape: shape,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
elevation: widget.elevation,
|
||||
color: backgroundColor,
|
||||
shadowColor: widget.shadowColor,
|
||||
@ -354,7 +369,7 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
static Widget _transparentInterior({ShapeBorder shape, Widget contents}) {
|
||||
static Widget _transparentInterior({ShapeBorder shape, Clip clipBehavior, Widget contents}) {
|
||||
return new ClipPath(
|
||||
child: new _ShapeBorderPaint(
|
||||
child: contents,
|
||||
@ -363,6 +378,7 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
|
||||
clipper: new ShapeBorderClipper(
|
||||
shape: shape,
|
||||
),
|
||||
clipBehavior: clipBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
@ -582,6 +598,7 @@ class _MaterialInterior extends ImplicitlyAnimatedWidget {
|
||||
Key key,
|
||||
@required this.child,
|
||||
@required this.shape,
|
||||
this.clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
@required this.elevation,
|
||||
@required this.color,
|
||||
@required this.shadowColor,
|
||||
@ -589,6 +606,7 @@ class _MaterialInterior extends ImplicitlyAnimatedWidget {
|
||||
@required Duration duration,
|
||||
}) : assert(child != null),
|
||||
assert(shape != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(elevation != null),
|
||||
assert(color != null),
|
||||
assert(shadowColor != null),
|
||||
@ -605,6 +623,9 @@ class _MaterialInterior extends ImplicitlyAnimatedWidget {
|
||||
/// determines the physical shape.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// The target z-coordinate at which to place this physical object.
|
||||
final double elevation;
|
||||
|
||||
@ -651,6 +672,7 @@ class _MaterialInteriorState extends AnimatedWidgetBaseState<_MaterialInterior>
|
||||
shape: shape,
|
||||
textDirection: Directionality.of(context)
|
||||
),
|
||||
clipBehavior: widget.clipBehavior,
|
||||
elevation: _elevation.evaluate(animation),
|
||||
color: widget.color,
|
||||
shadowColor: _shadowColor.evaluate(animation),
|
||||
|
59
packages/flutter/lib/src/painting/clip.dart
Normal file
59
packages/flutter/lib/src/painting/clip.dart
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show Canvas, Clip, Path, Paint, Rect, RRect;
|
||||
|
||||
/// Clip utilities used by [PaintingContext] and [TestRecordingPaintingContext].
|
||||
abstract class ClipContext {
|
||||
/// The canvas on which to paint.
|
||||
Canvas get canvas;
|
||||
|
||||
void _clipAndPaint(void canvasClipCall(bool doAntiAlias), Clip clipBehavior, Rect bounds, void painter()) {
|
||||
assert(canvasClipCall != null);
|
||||
canvas.save();
|
||||
switch (clipBehavior) {
|
||||
case Clip.none:
|
||||
break;
|
||||
case Clip.hardEdge:
|
||||
canvasClipCall(false);
|
||||
break;
|
||||
case Clip.antiAlias:
|
||||
canvasClipCall(true);
|
||||
break;
|
||||
case Clip.antiAliasWithSaveLayer:
|
||||
canvasClipCall(true);
|
||||
canvas.saveLayer(bounds, new Paint());
|
||||
break;
|
||||
}
|
||||
painter();
|
||||
if (clipBehavior == Clip.antiAliasWithSaveLayer) {
|
||||
canvas.restore();
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
/// Clip [canvas] with [Path] according to [Clip] and then paint. [canvas] is
|
||||
/// restored to the pre-clip status afterwards.
|
||||
///
|
||||
/// `bounds` is the saveLayer bounds used for [Clip.antiAliasWithSaveLayer].
|
||||
void clipPathAndPaint(Path path, Clip clipBehavior, Rect bounds, void painter()) {
|
||||
_clipAndPaint((bool doAntiAias) => canvas.clipPath(path, doAntiAlias: doAntiAias), clipBehavior, bounds, painter);
|
||||
}
|
||||
|
||||
/// Clip [canvas] with [Path] according to [RRect] and then paint. [canvas] is
|
||||
/// restored to the pre-clip status afterwards.
|
||||
///
|
||||
/// `bounds` is the saveLayer bounds used for [Clip.antiAliasWithSaveLayer].
|
||||
void clipRRectAndPaint(RRect rrect, Clip clipBehavior, Rect bounds, void painter()) {
|
||||
_clipAndPaint((bool doAntiAias) => canvas.clipRRect(rrect, doAntiAlias: doAntiAias), clipBehavior, bounds, painter);
|
||||
}
|
||||
|
||||
/// Clip [canvas] with [Path] according to [Rect] and then paint. [canvas] is
|
||||
/// restored to the pre-clip status afterwards.
|
||||
///
|
||||
/// `bounds` is the saveLayer bounds used for [Clip.antiAliasWithSaveLayer].
|
||||
void clipRectAndPaint(Rect rect, Clip clipBehavior, Rect bounds, void painter()) {
|
||||
_clipAndPaint((bool doAntiAias) => canvas.clipRect(rect, doAntiAlias: doAntiAias), clipBehavior, bounds, painter);
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:ui' as ui show Image, ImageFilter, Picture, Scene, SceneBuilder;
|
||||
import 'dart:ui' show Offset;
|
||||
import 'dart:ui' show Clip, Offset, defaultClipBehavior; // ignore: deprecated_member_use
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
@ -605,7 +605,8 @@ class ClipRectLayer extends ContainerLayer {
|
||||
///
|
||||
/// The [clipRect] property must be non-null before the compositing phase of
|
||||
/// the pipeline.
|
||||
ClipRectLayer({ this.clipRect });
|
||||
ClipRectLayer({ this.clipRect, Clip clipBehavior = Clip.antiAlias }) :
|
||||
_clipBehavior = clipBehavior, assert(clipBehavior != null), assert(clipBehavior != Clip.none);
|
||||
|
||||
/// The rectangle to clip in the parent's coordinate system.
|
||||
///
|
||||
@ -613,6 +614,15 @@ class ClipRectLayer extends ContainerLayer {
|
||||
/// (as described at [Layer]).
|
||||
Rect clipRect;
|
||||
|
||||
/// {@macro flutter.clipper.clipBehavior}
|
||||
Clip get clipBehavior => _clipBehavior;
|
||||
Clip _clipBehavior;
|
||||
set clipBehavior(Clip value) {
|
||||
assert(value != null);
|
||||
assert(value != Clip.none);
|
||||
_clipBehavior = value;
|
||||
}
|
||||
|
||||
@override
|
||||
S find<S>(Offset regionOffset) {
|
||||
if (!clipRect.contains(regionOffset))
|
||||
@ -628,7 +638,7 @@ class ClipRectLayer extends ContainerLayer {
|
||||
return true;
|
||||
}());
|
||||
if (enabled)
|
||||
builder.pushClipRect(clipRect.shift(layerOffset));
|
||||
builder.pushClipRect(clipRect.shift(layerOffset), clipBehavior: clipBehavior);
|
||||
addChildrenToScene(builder, layerOffset);
|
||||
if (enabled)
|
||||
builder.pop();
|
||||
@ -651,7 +661,8 @@ class ClipRRectLayer extends ContainerLayer {
|
||||
///
|
||||
/// The [clipRRect] property must be non-null before the compositing phase of
|
||||
/// the pipeline.
|
||||
ClipRRectLayer({ this.clipRRect });
|
||||
ClipRRectLayer({ this.clipRRect, Clip clipBehavior = Clip.antiAlias }) :
|
||||
_clipBehavior = clipBehavior, assert(clipBehavior != null), assert(clipBehavior != Clip.none);
|
||||
|
||||
/// The rounded-rect to clip in the parent's coordinate system.
|
||||
///
|
||||
@ -659,6 +670,15 @@ class ClipRRectLayer extends ContainerLayer {
|
||||
/// (as described at [Layer]).
|
||||
RRect clipRRect;
|
||||
|
||||
/// {@macro flutter.clipper.clipBehavior}
|
||||
Clip get clipBehavior => _clipBehavior;
|
||||
Clip _clipBehavior;
|
||||
set clipBehavior(Clip value) {
|
||||
assert(value != null);
|
||||
assert(value != Clip.none);
|
||||
_clipBehavior = value;
|
||||
}
|
||||
|
||||
@override
|
||||
S find<S>(Offset regionOffset) {
|
||||
if (!clipRRect.contains(regionOffset))
|
||||
@ -674,7 +694,7 @@ class ClipRRectLayer extends ContainerLayer {
|
||||
return true;
|
||||
}());
|
||||
if (enabled)
|
||||
builder.pushClipRRect(clipRRect.shift(layerOffset));
|
||||
builder.pushClipRRect(clipRRect.shift(layerOffset), clipBehavior: clipBehavior);
|
||||
addChildrenToScene(builder, layerOffset);
|
||||
if (enabled)
|
||||
builder.pop();
|
||||
@ -697,7 +717,8 @@ class ClipPathLayer extends ContainerLayer {
|
||||
///
|
||||
/// The [clipPath] property must be non-null before the compositing phase of
|
||||
/// the pipeline.
|
||||
ClipPathLayer({ this.clipPath });
|
||||
ClipPathLayer({ this.clipPath, Clip clipBehavior = Clip.antiAlias }) :
|
||||
_clipBehavior = clipBehavior, assert(clipBehavior != null), assert(clipBehavior != Clip.none);
|
||||
|
||||
/// The path to clip in the parent's coordinate system.
|
||||
///
|
||||
@ -705,6 +726,15 @@ class ClipPathLayer extends ContainerLayer {
|
||||
/// (as described at [Layer]).
|
||||
Path clipPath;
|
||||
|
||||
/// {@macro flutter.clipper.clipBehavior}
|
||||
Clip get clipBehavior => _clipBehavior;
|
||||
Clip _clipBehavior;
|
||||
set clipBehavior(Clip value) {
|
||||
assert(value != null);
|
||||
assert(value != Clip.none);
|
||||
_clipBehavior = value;
|
||||
}
|
||||
|
||||
@override
|
||||
S find<S>(Offset regionOffset) {
|
||||
if (!clipPath.contains(regionOffset))
|
||||
@ -720,7 +750,7 @@ class ClipPathLayer extends ContainerLayer {
|
||||
return true;
|
||||
}());
|
||||
if (enabled)
|
||||
builder.pushClipPath(clipPath.shift(layerOffset));
|
||||
builder.pushClipPath(clipPath.shift(layerOffset), clipBehavior: clipBehavior);
|
||||
addChildrenToScene(builder, layerOffset);
|
||||
if (enabled)
|
||||
builder.pop();
|
||||
@ -925,10 +955,12 @@ class PhysicalModelLayer extends ContainerLayer {
|
||||
/// The [clipPath], [elevation], and [color] arguments must not be null.
|
||||
PhysicalModelLayer({
|
||||
@required this.clipPath,
|
||||
this.clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
@required this.elevation,
|
||||
@required this.color,
|
||||
@required this.shadowColor,
|
||||
}) : assert(clipPath != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(elevation != null),
|
||||
assert(color != null),
|
||||
assert(shadowColor != null);
|
||||
@ -939,6 +971,9 @@ class PhysicalModelLayer extends ContainerLayer {
|
||||
/// (as described at [Layer]).
|
||||
Path clipPath;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
Clip clipBehavior;
|
||||
|
||||
/// The z-coordinate at which to place this physical object.
|
||||
///
|
||||
/// The scene must be explicitly recomposited after this property is changed
|
||||
@ -980,6 +1015,7 @@ class PhysicalModelLayer extends ContainerLayer {
|
||||
elevation: elevation,
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
clipBehavior: clipBehavior,
|
||||
);
|
||||
}
|
||||
addChildrenToScene(builder, layerOffset);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:developer';
|
||||
import 'dart:ui' as ui show PictureRecorder;
|
||||
import 'dart:ui' show Clip;
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -59,7 +60,7 @@ typedef void PaintingContextCallback(PaintingContext context, Offset offset);
|
||||
///
|
||||
/// New [PaintingContext] objects are created automatically when using
|
||||
/// [PaintingContext.repaintCompositedChild] and [pushLayer].
|
||||
class PaintingContext {
|
||||
class PaintingContext extends ClipContext {
|
||||
PaintingContext._(this._containerLayer, this.estimatedBounds)
|
||||
: assert(_containerLayer != null),
|
||||
assert(estimatedBounds != null);
|
||||
@ -195,6 +196,7 @@ class PaintingContext {
|
||||
/// The current canvas can change whenever you paint a child using this
|
||||
/// context, which means it's fragile to hold a reference to the canvas
|
||||
/// returned by this getter.
|
||||
@override
|
||||
Canvas get canvas {
|
||||
if (_canvas == null)
|
||||
_startRecording();
|
||||
@ -315,17 +317,13 @@ class PaintingContext {
|
||||
/// clip the painting done by [painter].
|
||||
/// * `painter` is a callback that will paint with the [clipRect] applied. This
|
||||
/// function calls the [painter] synchronously.
|
||||
void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter) {
|
||||
/// * `clipBehavior` controls how the rectangle is clipped.
|
||||
void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter, {Clip clipBehavior = Clip.antiAlias}) {
|
||||
final Rect offsetClipRect = clipRect.shift(offset);
|
||||
if (needsCompositing) {
|
||||
pushLayer(new ClipRectLayer(clipRect: offsetClipRect), painter, offset, childPaintBounds: offsetClipRect);
|
||||
pushLayer(new ClipRectLayer(clipRect: offsetClipRect, clipBehavior: clipBehavior), painter, offset, childPaintBounds: offsetClipRect);
|
||||
} else {
|
||||
canvas
|
||||
..save()
|
||||
..clipRect(offsetClipRect);
|
||||
painter(this, offset);
|
||||
canvas
|
||||
..restore();
|
||||
clipRectAndPaint(offsetClipRect, clipBehavior, offsetClipRect, () => painter(this, offset));
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,18 +339,16 @@ class PaintingContext {
|
||||
/// to use to clip the painting done by `painter`.
|
||||
/// * `painter` is a callback that will paint with the `clipRRect` applied. This
|
||||
/// function calls the `painter` synchronously.
|
||||
void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter) {
|
||||
/// * `clipBehavior` controls how the path is clipped.
|
||||
// ignore: deprecated_member_use
|
||||
void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter, {Clip clipBehavior = Clip.antiAlias}) {
|
||||
assert(clipBehavior != null);
|
||||
final Rect offsetBounds = bounds.shift(offset);
|
||||
final RRect offsetClipRRect = clipRRect.shift(offset);
|
||||
if (needsCompositing) {
|
||||
pushLayer(new ClipRRectLayer(clipRRect: offsetClipRRect), painter, offset, childPaintBounds: offsetBounds);
|
||||
pushLayer(new ClipRRectLayer(clipRRect: offsetClipRRect, clipBehavior: clipBehavior), painter, offset, childPaintBounds: offsetBounds);
|
||||
} else {
|
||||
canvas
|
||||
..save()
|
||||
..clipRRect(offsetClipRRect);
|
||||
painter(this, offset);
|
||||
canvas
|
||||
..restore();
|
||||
clipRRectAndPaint(offsetClipRRect, clipBehavior, offsetBounds, () => painter(this, offset));
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,18 +364,16 @@ class PaintingContext {
|
||||
/// clip the painting done by `painter`.
|
||||
/// * `painter` is a callback that will paint with the `clipPath` applied. This
|
||||
/// function calls the `painter` synchronously.
|
||||
void pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter) {
|
||||
/// * `clipBehavior` controls how the rounded rectangle is clipped.
|
||||
// ignore: deprecated_member_use
|
||||
void pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter, {Clip clipBehavior = Clip.antiAlias}) {
|
||||
assert(clipBehavior != null);
|
||||
final Rect offsetBounds = bounds.shift(offset);
|
||||
final Path offsetClipPath = clipPath.shift(offset);
|
||||
if (needsCompositing) {
|
||||
pushLayer(new ClipPathLayer(clipPath: offsetClipPath), painter, offset, childPaintBounds: offsetBounds);
|
||||
pushLayer(new ClipPathLayer(clipPath: offsetClipPath, clipBehavior: clipBehavior), painter, offset, childPaintBounds: offsetBounds);
|
||||
} else {
|
||||
canvas
|
||||
..save()
|
||||
..clipPath(clipPath.shift(offset));
|
||||
painter(this, offset);
|
||||
canvas
|
||||
..restore();
|
||||
clipPathAndPaint(offsetClipPath, clipBehavior, offsetBounds, () => painter(this, offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'dart:ui' as ui show ImageFilter, Gradient, Image;
|
||||
import 'dart:ui' show Clip, defaultClipBehavior; // ignore: deprecated_member_use
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -1116,8 +1117,9 @@ class ShapeBorderClipper extends CustomClipper<Path> {
|
||||
abstract class _RenderCustomClip<T> extends RenderProxyBox {
|
||||
_RenderCustomClip({
|
||||
RenderBox child,
|
||||
CustomClipper<T> clipper
|
||||
}) : _clipper = clipper, super(child);
|
||||
CustomClipper<T> clipper,
|
||||
this.clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
}) : _clipper = clipper, assert(clipBehavior != null), assert(clipBehavior != Clip.none), super(child);
|
||||
|
||||
/// If non-null, determines which clip to use on the child.
|
||||
CustomClipper<T> get clipper => _clipper;
|
||||
@ -1160,6 +1162,13 @@ abstract class _RenderCustomClip<T> extends RenderProxyBox {
|
||||
T get _defaultClip;
|
||||
T _clip;
|
||||
|
||||
/// {@template flutter.clipper.clipBehavior}
|
||||
/// Controls how to clip (default to [Clip.antiAlias]).
|
||||
///
|
||||
/// [Clip.none] is not allowed here.
|
||||
/// {@endtemplate}
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
final Size oldSize = hasSize ? size : null;
|
||||
@ -1220,8 +1229,9 @@ class RenderClipRect extends _RenderCustomClip<Rect> {
|
||||
/// the child.
|
||||
RenderClipRect({
|
||||
RenderBox child,
|
||||
CustomClipper<Rect> clipper
|
||||
}) : super(child: child, clipper: clipper);
|
||||
CustomClipper<Rect> clipper,
|
||||
Clip clipBehavior = Clip.antiAlias,
|
||||
}) : super(child: child, clipper: clipper, clipBehavior: clipBehavior);
|
||||
|
||||
@override
|
||||
Rect get _defaultClip => Offset.zero & size;
|
||||
@ -1241,7 +1251,7 @@ class RenderClipRect extends _RenderCustomClip<Rect> {
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (child != null) {
|
||||
_updateClip();
|
||||
context.pushClipRect(needsCompositing, offset, _clip, super.paint);
|
||||
context.pushClipRect(needsCompositing, offset, _clip, super.paint, clipBehavior: clipBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1274,7 +1284,8 @@ class RenderClipRRect extends _RenderCustomClip<RRect> {
|
||||
RenderBox child,
|
||||
BorderRadius borderRadius = BorderRadius.zero,
|
||||
CustomClipper<RRect> clipper,
|
||||
}) : _borderRadius = borderRadius, super(child: child, clipper: clipper) {
|
||||
Clip clipBehavior = Clip.antiAlias,
|
||||
}) : _borderRadius = borderRadius, super(child: child, clipper: clipper, clipBehavior: clipBehavior) {
|
||||
assert(_borderRadius != null || clipper != null);
|
||||
}
|
||||
|
||||
@ -1312,7 +1323,7 @@ class RenderClipRRect extends _RenderCustomClip<RRect> {
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (child != null) {
|
||||
_updateClip();
|
||||
context.pushClipRRect(needsCompositing, offset, _clip.outerRect, _clip, super.paint);
|
||||
context.pushClipRRect(needsCompositing, offset, _clip.outerRect, _clip, super.paint, clipBehavior: clipBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1341,8 +1352,9 @@ class RenderClipOval extends _RenderCustomClip<Rect> {
|
||||
/// position of the child.
|
||||
RenderClipOval({
|
||||
RenderBox child,
|
||||
CustomClipper<Rect> clipper
|
||||
}) : super(child: child, clipper: clipper);
|
||||
CustomClipper<Rect> clipper,
|
||||
Clip clipBehavior = Clip.antiAlias,
|
||||
}) : super(child: child, clipper: clipper, clipBehavior: clipBehavior);
|
||||
|
||||
Rect _cachedRect;
|
||||
Path _cachedPath;
|
||||
@ -1376,7 +1388,7 @@ class RenderClipOval extends _RenderCustomClip<Rect> {
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (child != null) {
|
||||
_updateClip();
|
||||
context.pushClipPath(needsCompositing, offset, _clip, _getClipPath(_clip), super.paint);
|
||||
context.pushClipPath(needsCompositing, offset, _clip, _getClipPath(_clip), super.paint, clipBehavior: clipBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1413,8 +1425,9 @@ class RenderClipPath extends _RenderCustomClip<Path> {
|
||||
/// efficiently.
|
||||
RenderClipPath({
|
||||
RenderBox child,
|
||||
CustomClipper<Path> clipper
|
||||
}) : super(child: child, clipper: clipper);
|
||||
CustomClipper<Path> clipper,
|
||||
Clip clipBehavior = Clip.antiAlias,
|
||||
}) : super(child: child, clipper: clipper, clipBehavior: clipBehavior);
|
||||
|
||||
@override
|
||||
Path get _defaultClip => new Path()..addRect(Offset.zero & size);
|
||||
@ -1434,7 +1447,7 @@ class RenderClipPath extends _RenderCustomClip<Path> {
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (child != null) {
|
||||
_updateClip();
|
||||
context.pushClipPath(needsCompositing, offset, Offset.zero & size, _clip, super.paint);
|
||||
context.pushClipPath(needsCompositing, offset, Offset.zero & size, _clip, super.paint, clipBehavior: clipBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1462,14 +1475,16 @@ abstract class _RenderPhysicalModelBase<T> extends _RenderCustomClip<T> {
|
||||
@required double elevation,
|
||||
@required Color color,
|
||||
@required Color shadowColor,
|
||||
Clip clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
CustomClipper<T> clipper,
|
||||
}) : assert(elevation != null),
|
||||
assert(color != null),
|
||||
assert(shadowColor != null),
|
||||
assert(clipBehavior != null),
|
||||
_elevation = elevation,
|
||||
_color = color,
|
||||
_shadowColor = shadowColor,
|
||||
super(child: child, clipper: clipper);
|
||||
super(child: child, clipBehavior: clipBehavior, clipper: clipper);
|
||||
|
||||
/// The z-coordinate at which to place this material.
|
||||
///
|
||||
@ -1539,17 +1554,20 @@ class RenderPhysicalModel extends _RenderPhysicalModelBase<RRect> {
|
||||
RenderPhysicalModel({
|
||||
RenderBox child,
|
||||
BoxShape shape = BoxShape.rectangle,
|
||||
Clip clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
BorderRadius borderRadius,
|
||||
double elevation = 0.0,
|
||||
@required Color color,
|
||||
Color shadowColor = const Color(0xFF000000),
|
||||
}) : assert(shape != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(elevation != null),
|
||||
assert(color != null),
|
||||
assert(shadowColor != null),
|
||||
_shape = shape,
|
||||
_borderRadius = borderRadius,
|
||||
super(
|
||||
clipBehavior: clipBehavior,
|
||||
child: child,
|
||||
elevation: elevation,
|
||||
color: color,
|
||||
@ -1638,6 +1656,7 @@ class RenderPhysicalModel extends _RenderPhysicalModelBase<RRect> {
|
||||
if (needsCompositing) {
|
||||
final PhysicalModelLayer physicalModel = new PhysicalModelLayer(
|
||||
clipPath: offsetRRectAsPath,
|
||||
clipBehavior: clipBehavior,
|
||||
elevation: paintShadows ? elevation : 0.0,
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
@ -1662,10 +1681,7 @@ class RenderPhysicalModel extends _RenderPhysicalModelBase<RRect> {
|
||||
);
|
||||
}
|
||||
canvas.drawRRect(offsetRRect, new Paint()..color = color);
|
||||
canvas.save();
|
||||
canvas.clipRRect(offsetRRect);
|
||||
super.paint(context, offset);
|
||||
canvas.restore();
|
||||
context.clipRRectAndPaint(offsetRRect, clipBehavior, offsetBounds, () => super.paint(context, offset));
|
||||
assert(context.canvas == canvas, 'canvas changed even though needsCompositing was false');
|
||||
}
|
||||
}
|
||||
@ -1697,6 +1713,7 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase<Path> {
|
||||
RenderPhysicalShape({
|
||||
RenderBox child,
|
||||
@required CustomClipper<Path> clipper,
|
||||
Clip clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
double elevation = 0.0,
|
||||
@required Color color,
|
||||
Color shadowColor = const Color(0xFF000000),
|
||||
@ -1710,6 +1727,7 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase<Path> {
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
clipper: clipper,
|
||||
clipBehavior: clipBehavior
|
||||
);
|
||||
|
||||
@override
|
||||
@ -1751,6 +1769,7 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase<Path> {
|
||||
if (needsCompositing) {
|
||||
final PhysicalModelLayer physicalModel = new PhysicalModelLayer(
|
||||
clipPath: offsetPath,
|
||||
clipBehavior: clipBehavior,
|
||||
elevation: paintShadows ? elevation : 0.0,
|
||||
color: color,
|
||||
shadowColor: shadowColor,
|
||||
@ -1775,10 +1794,7 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase<Path> {
|
||||
);
|
||||
}
|
||||
canvas.drawPath(offsetPath, new Paint()..color = color..style = PaintingStyle.fill);
|
||||
canvas.save();
|
||||
canvas.clipPath(offsetPath);
|
||||
super.paint(context, offset);
|
||||
canvas.restore();
|
||||
context.clipPathAndPaint(offsetPath, clipBehavior, offsetBounds, () => super.paint(context, offset));
|
||||
assert(context.canvas == canvas, 'canvas changed even though needsCompositing was false');
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui show Image, ImageFilter;
|
||||
import 'dart:ui' show Clip, defaultClipBehavior; // ignore: deprecated_member_use
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@ -476,13 +477,16 @@ class ClipRect extends SingleChildRenderObjectWidget {
|
||||
///
|
||||
/// If [clipper] is null, the clip will match the layout size and position of
|
||||
/// the child.
|
||||
const ClipRect({ Key key, this.clipper, Widget child }) : super(key: key, child: child);
|
||||
const ClipRect({ Key key, this.clipper, this.clipBehavior = Clip.antiAlias, Widget child }) : super(key: key, child: child);
|
||||
|
||||
/// If non-null, determines which clip to use.
|
||||
final CustomClipper<Rect> clipper;
|
||||
|
||||
/// {@macro flutter.widget.clipper.clipBehavior}
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
RenderClipRect createRenderObject(BuildContext context) => new RenderClipRect(clipper: clipper);
|
||||
RenderClipRect createRenderObject(BuildContext context) => new RenderClipRect(clipper: clipper, clipBehavior: clipBehavior);
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderClipRect renderObject) {
|
||||
@ -524,8 +528,10 @@ class ClipRRect extends SingleChildRenderObjectWidget {
|
||||
Key key,
|
||||
this.borderRadius,
|
||||
this.clipper,
|
||||
this.clipBehavior = Clip.antiAlias,
|
||||
Widget child,
|
||||
}) : assert(borderRadius != null || clipper != null),
|
||||
assert(clipBehavior != null),
|
||||
super(key: key, child: child);
|
||||
|
||||
/// The border radius of the rounded corners.
|
||||
@ -539,8 +545,11 @@ class ClipRRect extends SingleChildRenderObjectWidget {
|
||||
/// If non-null, determines which clip to use.
|
||||
final CustomClipper<RRect> clipper;
|
||||
|
||||
/// {@macro flutter.widget.clipper.clipBehavior}
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
RenderClipRRect createRenderObject(BuildContext context) => new RenderClipRRect(borderRadius: borderRadius, clipper: clipper);
|
||||
RenderClipRRect createRenderObject(BuildContext context) => new RenderClipRRect(borderRadius: borderRadius, clipper: clipper, clipBehavior: clipBehavior);
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderClipRRect renderObject) {
|
||||
@ -575,7 +584,7 @@ class ClipOval extends SingleChildRenderObjectWidget {
|
||||
///
|
||||
/// If [clipper] is null, the oval will be inscribed into the layout size and
|
||||
/// position of the child.
|
||||
const ClipOval({ Key key, this.clipper, Widget child }) : super(key: key, child: child);
|
||||
const ClipOval({ Key key, this.clipper, this.clipBehavior = Clip.antiAlias, Widget child }) : super(key: key, child: child);
|
||||
|
||||
/// If non-null, determines which clip to use.
|
||||
///
|
||||
@ -588,8 +597,11 @@ class ClipOval extends SingleChildRenderObjectWidget {
|
||||
/// object) instead.
|
||||
final CustomClipper<Rect> clipper;
|
||||
|
||||
/// {@macro flutter.widget.clipper.clipBehavior}
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
RenderClipOval createRenderObject(BuildContext context) => new RenderClipOval(clipper: clipper);
|
||||
RenderClipOval createRenderObject(BuildContext context) => new RenderClipOval(clipper: clipper, clipBehavior: clipBehavior);
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderClipOval renderObject) {
|
||||
@ -627,7 +639,7 @@ class ClipPath extends SingleChildRenderObjectWidget {
|
||||
/// size and location of the child. However, rather than use this default,
|
||||
/// consider using a [ClipRect], which can achieve the same effect more
|
||||
/// efficiently.
|
||||
const ClipPath({ Key key, this.clipper, Widget child }) : super(key: key, child: child);
|
||||
const ClipPath({ Key key, this.clipper, this.clipBehavior = Clip.antiAlias, Widget child }) : super(key: key, child: child);
|
||||
|
||||
/// If non-null, determines which clip to use.
|
||||
///
|
||||
@ -636,8 +648,11 @@ class ClipPath extends SingleChildRenderObjectWidget {
|
||||
/// efficient way of obtaining that effect.
|
||||
final CustomClipper<Path> clipper;
|
||||
|
||||
/// {@macro flutter.widget.clipper.clipBehavior}
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
RenderClipPath createRenderObject(BuildContext context) => new RenderClipPath(clipper: clipper);
|
||||
RenderClipPath createRenderObject(BuildContext context) => new RenderClipPath(clipper: clipper, clipBehavior: clipBehavior);
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderClipPath renderObject) {
|
||||
@ -677,6 +692,7 @@ class PhysicalModel extends SingleChildRenderObjectWidget {
|
||||
const PhysicalModel({
|
||||
Key key,
|
||||
this.shape = BoxShape.rectangle,
|
||||
this.clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
this.borderRadius,
|
||||
this.elevation = 0.0,
|
||||
@required this.color,
|
||||
@ -691,6 +707,9 @@ class PhysicalModel extends SingleChildRenderObjectWidget {
|
||||
/// The type of shape.
|
||||
final BoxShape shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// The border radius of the rounded corners.
|
||||
///
|
||||
/// Values are clamped so that horizontal and vertical radii sums do not
|
||||
@ -712,6 +731,7 @@ class PhysicalModel extends SingleChildRenderObjectWidget {
|
||||
RenderPhysicalModel createRenderObject(BuildContext context) {
|
||||
return new RenderPhysicalModel(
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
borderRadius: borderRadius,
|
||||
elevation: elevation, color: color,
|
||||
shadowColor: shadowColor,
|
||||
@ -760,11 +780,13 @@ class PhysicalShape extends SingleChildRenderObjectWidget {
|
||||
const PhysicalShape({
|
||||
Key key,
|
||||
@required this.clipper,
|
||||
this.clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
this.elevation = 0.0,
|
||||
@required this.color,
|
||||
this.shadowColor = const Color(0xFF000000),
|
||||
Widget child,
|
||||
}) : assert(clipper != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(elevation != null),
|
||||
assert(color != null),
|
||||
assert(shadowColor != null),
|
||||
@ -777,6 +799,9 @@ class PhysicalShape extends SingleChildRenderObjectWidget {
|
||||
/// shape for use with this widget.
|
||||
final CustomClipper<Path> clipper;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// The z-coordinate at which to place this physical object.
|
||||
final double elevation;
|
||||
|
||||
@ -790,6 +815,7 @@ class PhysicalShape extends SingleChildRenderObjectWidget {
|
||||
RenderPhysicalShape createRenderObject(BuildContext context) {
|
||||
return new RenderPhysicalShape(
|
||||
clipper: clipper,
|
||||
clipBehavior: clipBehavior,
|
||||
elevation: elevation,
|
||||
color: color,
|
||||
shadowColor: shadowColor
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show Clip, defaultClipBehavior; // ignore: deprecated_member_use
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@ -1181,6 +1183,7 @@ class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget {
|
||||
Key key,
|
||||
@required this.child,
|
||||
@required this.shape,
|
||||
this.clipBehavior = defaultClipBehavior, // ignore: deprecated_member_use
|
||||
this.borderRadius = BorderRadius.zero,
|
||||
@required this.elevation,
|
||||
@required this.color,
|
||||
@ -1191,6 +1194,7 @@ class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget {
|
||||
@required Duration duration,
|
||||
}) : assert(child != null),
|
||||
assert(shape != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(borderRadius != null),
|
||||
assert(elevation != null),
|
||||
assert(color != null),
|
||||
@ -1209,6 +1213,9 @@ class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget {
|
||||
/// This property is not animated.
|
||||
final BoxShape shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// The target border radius of the rounded corners for a rectangle shape.
|
||||
final BorderRadius borderRadius;
|
||||
|
||||
@ -1262,6 +1269,7 @@ class _AnimatedPhysicalModelState extends AnimatedWidgetBaseState<AnimatedPhysic
|
||||
return new PhysicalModel(
|
||||
child: widget.child,
|
||||
shape: widget.shape,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
borderRadius: _borderRadius.evaluate(animation),
|
||||
elevation: _elevation.evaluate(animation),
|
||||
color: widget.animateColor ? _color.evaluate(animation) : widget.color,
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show Clip;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
@ -90,7 +92,7 @@ class TestRecordingCanvas implements Canvas {
|
||||
}
|
||||
|
||||
/// A [PaintingContext] for tests that use [TestRecordingCanvas].
|
||||
class TestRecordingPaintingContext implements PaintingContext {
|
||||
class TestRecordingPaintingContext extends ClipContext implements PaintingContext {
|
||||
/// Creates a [PaintingContext] for tests that use [TestRecordingCanvas].
|
||||
TestRecordingPaintingContext(this.canvas);
|
||||
|
||||
@ -103,28 +105,19 @@ class TestRecordingPaintingContext implements PaintingContext {
|
||||
}
|
||||
|
||||
@override
|
||||
void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter) {
|
||||
canvas.save();
|
||||
canvas.clipRect(clipRect.shift(offset));
|
||||
painter(this, offset);
|
||||
canvas.restore();
|
||||
void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter, {Clip clipBehavior = Clip.antiAlias}) {
|
||||
clipRectAndPaint(clipRect.shift(offset), clipBehavior, clipRect.shift(offset), () => painter(this, offset));
|
||||
}
|
||||
|
||||
@override
|
||||
void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter) {
|
||||
canvas.save();
|
||||
canvas.clipRRect(clipRRect.shift(offset));
|
||||
painter(this, offset);
|
||||
canvas.restore();
|
||||
void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter, {Clip clipBehavior = Clip.antiAlias}) {
|
||||
assert(clipBehavior != null);
|
||||
clipRRectAndPaint(clipRRect.shift(offset), clipBehavior, bounds.shift(offset), () => painter(this, offset));
|
||||
}
|
||||
|
||||
@override
|
||||
void pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter) {
|
||||
canvas
|
||||
..save()
|
||||
..clipPath(clipPath.shift(offset));
|
||||
painter(this, offset);
|
||||
canvas.restore();
|
||||
void pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter, {Clip clipBehavior = Clip.antiAlias}) {
|
||||
clipPathAndPaint(clipPath.shift(offset), clipBehavior, bounds.shift(offset), () => painter(this, offset));
|
||||
}
|
||||
|
||||
@override
|
||||
|
Loading…
x
Reference in New Issue
Block a user