Commit eaab8fa1 authored by Adam Barth's avatar Adam Barth

Merge pull request #735 from abarth/custom_clip

Add custom clipping to ClipRect and ClipOval
parents 97599711 f6672660
...@@ -561,15 +561,61 @@ class RenderShaderMask extends RenderProxyBox { ...@@ -561,15 +561,61 @@ class RenderShaderMask extends RenderProxyBox {
} }
} }
abstract class CustomClipper<T> {
T getClip(Size size);
bool shouldRepaint(CustomClipper oldClipper);
}
abstract class _RenderCustomClip<T> extends RenderProxyBox {
_RenderCustomClip({
RenderBox child,
CustomClipper<T> clipper
}) : _clipper = clipper, super(child);
CustomClipper<T> get clipper => _clipper;
CustomClipper<T> _clipper;
void set clipper (CustomClipper<T> newClipper) {
if (_clipper == newClipper)
return;
CustomClipper<T> oldClipper = _clipper;
_clipper = newClipper;
if (newClipper == null) {
assert(oldClipper != null);
markNeedsPaint();
} else if (oldClipper == null ||
oldClipper.runtimeType != oldClipper.runtimeType ||
newClipper.shouldRepaint(oldClipper)) {
markNeedsPaint();
}
}
T get _defaultClip;
T get _clip => _clipper?.getClip(size) ?? _defaultClip;
}
/// Clips its child using a rectangle /// Clips its child using a rectangle
/// ///
/// Prevents its child from painting outside its bounds. /// Prevents its child from painting outside its bounds.
class RenderClipRect extends RenderProxyBox { class RenderClipRect extends _RenderCustomClip<Rect> {
RenderClipRect({ RenderBox child }) : super(child); RenderClipRect({
RenderBox child,
CustomClipper<Rect> clipper
}) : super(child: child, clipper: clipper);
Rect get _defaultClip => Point.origin & size;
bool hitTest(HitTestResult result, { Point position }) {
if (_clipper != null) {
Rect clipRect = _clip;
if (!clipRect.contains(position))
return false;
}
return super.hitTest(result, position: position);
}
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.pushClipRect(needsCompositing, offset, Point.origin & size, super.paint); context.pushClipRect(needsCompositing, offset, _clip, super.paint);
} }
} }
...@@ -579,8 +625,11 @@ class RenderClipRect extends RenderProxyBox { ...@@ -579,8 +625,11 @@ class RenderClipRect extends RenderProxyBox {
/// y radius values and prevents its child from painting outside that rounded /// y radius values and prevents its child from painting outside that rounded
/// rectangle. /// rectangle.
class RenderClipRRect extends RenderProxyBox { class RenderClipRRect extends RenderProxyBox {
RenderClipRRect({ RenderBox child, double xRadius, double yRadius }) RenderClipRRect({
: _xRadius = xRadius, _yRadius = yRadius, super(child) { RenderBox child,
double xRadius,
double yRadius
}) : _xRadius = xRadius, _yRadius = yRadius, super(child) {
assert(_xRadius != null); assert(_xRadius != null);
assert(_yRadius != null); assert(_yRadius != null);
} }
...@@ -626,8 +675,11 @@ class RenderClipRRect extends RenderProxyBox { ...@@ -626,8 +675,11 @@ class RenderClipRRect extends RenderProxyBox {
/// ///
/// Inscribes an oval into its layout dimensions and prevents its child from /// Inscribes an oval into its layout dimensions and prevents its child from
/// painting outside that oval. /// painting outside that oval.
class RenderClipOval extends RenderProxyBox { class RenderClipOval extends _RenderCustomClip<Rect> {
RenderClipOval({ RenderBox child }) : super(child); RenderClipOval({
RenderBox child,
CustomClipper<Rect> clipper
}) : super(child: child, clipper: clipper);
Rect _cachedRect; Rect _cachedRect;
Path _cachedPath; Path _cachedPath;
...@@ -640,10 +692,13 @@ class RenderClipOval extends RenderProxyBox { ...@@ -640,10 +692,13 @@ class RenderClipOval extends RenderProxyBox {
return _cachedPath; return _cachedPath;
} }
Rect get _defaultClip => Point.origin & size;
bool hitTest(HitTestResult result, { Point position }) { bool hitTest(HitTestResult result, { Point position }) {
Point center = size.center(Point.origin); Rect clipBounds = _clip;
Offset offset = new Offset((position.x - center.x) / size.width, Point center = clipBounds.center;
(position.y - center.y) / size.height); Offset offset = new Offset((position.x - center.x) / clipBounds.width,
(position.y - center.y) / clipBounds.height);
if (offset.distance > 0.5) if (offset.distance > 0.5)
return false; return false;
return super.hitTest(result, position: position); return super.hitTest(result, position: position);
...@@ -651,8 +706,8 @@ class RenderClipOval extends RenderProxyBox { ...@@ -651,8 +706,8 @@ class RenderClipOval extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
Rect bounds = Point.origin & size; Rect clipBounds = _clip;
context.pushClipPath(needsCompositing, offset, bounds, _getClipPath(bounds), super.paint); context.pushClipPath(needsCompositing, offset, clipBounds, _getClipPath(clipBounds), super.paint);
} }
} }
} }
......
...@@ -21,6 +21,7 @@ export 'package:flutter/rendering.dart' show ...@@ -21,6 +21,7 @@ export 'package:flutter/rendering.dart' show
Canvas, Canvas,
Color, Color,
ColorFilter, ColorFilter,
CustomClipper,
CustomPainter, CustomPainter,
EdgeDims, EdgeDims,
FlexAlignItems, FlexAlignItems,
...@@ -160,8 +161,19 @@ class CustomPaint extends OneChildRenderObjectWidget { ...@@ -160,8 +161,19 @@ class CustomPaint extends OneChildRenderObjectWidget {
} }
class ClipRect extends OneChildRenderObjectWidget { class ClipRect extends OneChildRenderObjectWidget {
ClipRect({ Key key, Widget child }) : super(key: key, child: child); ClipRect({ Key key, this.clipper, Widget child }) : super(key: key, child: child);
RenderClipRect createRenderObject() => new RenderClipRect();
final CustomClipper<Rect> clipper;
RenderClipRect createRenderObject() => new RenderClipRect(clipper: clipper);
void updateRenderObject(RenderClipRect renderObject, ClipRect oldWidget) {
renderObject.clipper = clipper;
}
void didUnmountRenderObject(RenderClipRect renderObject) {
renderObject.clipper = null;
}
} }
class ClipRRect extends OneChildRenderObjectWidget { class ClipRRect extends OneChildRenderObjectWidget {
...@@ -180,8 +192,19 @@ class ClipRRect extends OneChildRenderObjectWidget { ...@@ -180,8 +192,19 @@ class ClipRRect extends OneChildRenderObjectWidget {
} }
class ClipOval extends OneChildRenderObjectWidget { class ClipOval extends OneChildRenderObjectWidget {
ClipOval({ Key key, Widget child }) : super(key: key, child: child); ClipOval({ Key key, this.clipper, Widget child }) : super(key: key, child: child);
RenderClipOval createRenderObject() => new RenderClipOval();
final CustomClipper<Rect> clipper;
RenderClipOval createRenderObject() => new RenderClipOval(clipper: clipper);
void updateRenderObject(RenderClipOval renderObject, ClipOval oldWidget) {
renderObject.clipper = clipper;
}
void didUnmountRenderObject(RenderClipOval renderObject) {
renderObject.clipper = null;
}
} }
......
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