Commit 8b16c025 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add custom clipping to ClipRRect (#6346)

Fixes #773
parent 32037579
...@@ -1015,25 +1015,30 @@ class RenderClipRect extends _RenderCustomClip<Rect> { ...@@ -1015,25 +1015,30 @@ class RenderClipRect extends _RenderCustomClip<Rect> {
/// Clips its child using a rounded rectangle. /// Clips its child using a rounded rectangle.
/// ///
/// Creates a rounded rectangle from its layout dimensions and the given border /// By default, [RenderClipRRect] uses its own bounds as the base rectangle for
/// radius and prevents its child from painting outside that rounded /// the clip, but the size and location of the clip can be customized using a
/// rectangle. /// custom [clipper].
class RenderClipRRect extends RenderProxyBox { class RenderClipRRect extends _RenderCustomClip<RRect> {
/// Creates a rounded-rectangular clip. /// Creates a rounded-rectangular clip.
/// ///
/// The [borderRadius] defaults to [BorderRadius.zero], i.e. a rectangle with /// The [borderRadius] defaults to [BorderRadius.zero], i.e. a rectangle with
/// right-angled corners. /// right-angled corners.
///
/// If [clipper] is non-null, then [borderRadius] is ignored.
RenderClipRRect({ RenderClipRRect({
RenderBox child, RenderBox child,
BorderRadius borderRadius: BorderRadius.zero BorderRadius borderRadius: BorderRadius.zero,
}) : _borderRadius = borderRadius, super(child) { CustomClipper<RRect> clipper,
assert(_borderRadius != null); }) : _borderRadius = borderRadius, super(child: child, clipper: clipper) {
assert(_borderRadius != null || clipper != null);
} }
/// The border radius of the rounded corners.. /// The border radius of the rounded corners.
/// ///
/// Values are clamped so that horizontal and vertical radii sums do not /// Values are clamped so that horizontal and vertical radii sums do not
/// exceed width/height. /// exceed width/height.
///
/// This value is ignored if [clipper] is non-null.
BorderRadius get borderRadius => _borderRadius; BorderRadius get borderRadius => _borderRadius;
BorderRadius _borderRadius; BorderRadius _borderRadius;
set borderRadius (BorderRadius value) { set borderRadius (BorderRadius value) {
...@@ -1041,19 +1046,28 @@ class RenderClipRRect extends RenderProxyBox { ...@@ -1041,19 +1046,28 @@ class RenderClipRRect extends RenderProxyBox {
if (_borderRadius == value) if (_borderRadius == value)
return; return;
_borderRadius = value; _borderRadius = value;
markNeedsPaint(); _markNeedsClip();
} }
// TODO(ianh): either convert this to the CustomClipper world, or @override
// TODO(ianh): implement describeApproximatePaintClip for this class RRect get _defaultClip => _borderRadius.toRRect(Point.origin & size);
// TODO(ianh): implement hit testing for this class
@override
bool hitTest(HitTestResult result, { Point position }) {
if (_clipper != null) {
_updateClip();
assert(_clip != null);
if (!_clip.contains(position))
return false;
}
return super.hitTest(result, position: position);
}
@override @override
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
Rect rect = Point.origin & size; _updateClip();
RRect rrect = borderRadius.toRRect(rect); context.pushClipRRect(needsCompositing, offset, _clip.outerRect, _clip, super.paint);
context.pushClipRRect(needsCompositing, offset, rect, rrect, super.paint);
} }
} }
} }
......
...@@ -270,30 +270,44 @@ class ClipRect extends SingleChildRenderObjectWidget { ...@@ -270,30 +270,44 @@ class ClipRect extends SingleChildRenderObjectWidget {
/// A widget that clips its child using a rounded rectangle. /// A widget that clips its child using a rounded rectangle.
/// ///
/// Creates a rounded rectangle from its layout dimensions and the given x and /// By default, [ClipRRect] uses its own bounds as the base rectangle for the
/// y radius values and prevents its child from painting outside that rounded /// clip, but the size and location of the clip can be customized using a custom
/// rectangle. /// [clipper].
class ClipRRect extends SingleChildRenderObjectWidget { class ClipRRect extends SingleChildRenderObjectWidget {
/// Creates a rounded-rectangular clip. /// Creates a rounded-rectangular clip.
///
/// The [borderRadius] defaults to [BorderRadius.zero], i.e. a rectangle with
/// right-angled corners.
///
/// If [clipper] is non-null, then [borderRadius] is ignored.
ClipRRect({ ClipRRect({
Key key, Key key,
@required this.borderRadius, this.borderRadius,
Widget child this.clipper,
}) : super(key: key, child: child); Widget child,
}) : super(key: key, child: child) {
assert(borderRadius != null || clipper != null);
}
/// The border radius of the rounded corners. /// The border radius of the rounded corners.
/// ///
/// Values are clamped to be between zero and half the width of the render /// Values are clamped so that horizontal and vertical radii sums do not
/// object. /// exceed width/height.
///
/// This value is ignored if [clipper] is non-null.
final BorderRadius borderRadius; final BorderRadius borderRadius;
/// If non-null, determines which clip to use.
final CustomClipper<RRect> clipper;
@override @override
RenderClipRRect createRenderObject(BuildContext context) => new RenderClipRRect(borderRadius: borderRadius); RenderClipRRect createRenderObject(BuildContext context) => new RenderClipRRect(borderRadius: borderRadius, clipper: clipper);
@override @override
void updateRenderObject(BuildContext context, RenderClipRRect renderObject) { void updateRenderObject(BuildContext context, RenderClipRRect renderObject) {
renderObject renderObject
..borderRadius = borderRadius; ..borderRadius = borderRadius
..clipper = clipper;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment