How to draw a custom rounded rectangle border (ShapeBorder), in Flutter?
How to draw a custom rounded rectangle border (ShapeBorder), in Flutter?
I'm trying to extend the ShapeBorder
class to add some functionality. But just playing around with the paint
method, I found something that I did not expect:
ShapeBorder
paint
The corners of the border and the corners of the rectangle do not seem to match. I used the following code:
class CustomRoundedRectangleBorder extends ShapeBorder {
final double borderWidth;
final BorderRadius borderRadius;
const CustomRoundedRectangleBorder({
this.borderWidth: 1.0,
this.borderRadius: BorderRadius.zero,
})
: assert(borderRadius != null);
@override
EdgeInsetsGeometry get dimensions {
return new EdgeInsets.all(borderWidth);
}
@override
ShapeBorder scale(double t) {
return new CustomRoundedRectangleBorder(
borderWidth: borderWidth * (t),
borderRadius: borderRadius * (t),
);
}
@override
ShapeBorder lerpFrom(ShapeBorder a, double t) {
assert(t != null);
if (a is CustomRoundedRectangleBorder) {
return new CustomRoundedRectangleBorder(
borderWidth: ui.lerpDouble(a.borderWidth, borderWidth, t),
borderRadius: BorderRadius.lerp(a.borderRadius, borderRadius, t),
);
}
return super.lerpFrom(a, t);
}
@override
ShapeBorder lerpTo(ShapeBorder b, double t) {
assert(t != null);
if (b is CustomRoundedRectangleBorder) {
return new CustomRoundedRectangleBorder(
borderWidth: ui.lerpDouble(borderWidth, b.borderWidth, t),
borderRadius: BorderRadius.lerp(borderRadius, b.borderRadius, t),
);
}
return super.lerpTo(b, t);
}
@override
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
return new Path()
..addRRect(borderRadius.resolve(textDirection).toRRect(rect).deflate(
borderWidth));
}
@override
Path getOuterPath(Rect rect, { TextDirection textDirection }) {
return new Path()
..addRRect(borderRadius.resolve(textDirection).toRRect(rect));
}
@override
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) {
rect = rect.deflate(borderWidth / 2.0);
Paint paint;
final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect);
paint = new Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = borderWidth;
canvas.drawRRect(borderRect, paint);
}
}
And created the rectangle as follows:
new Container(
height: 100.0,
width: 200.0,
padding: new EdgeInsets.all(10.0),
decoration: new ShapeDecoration(
color: Colors.black,
shape: new CustomRoundedRectangleBorder(
borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
borderWidth: 10.0,
),
// side: new BorderSide(color: Colors.white)
),
child: new Center(child: new Text("My Button"),),
),
I feel like the Flutter source code takes a similar approach, but perhaps I'm not seeing something.
EDIT
Changing the style
of my paint
to PaintingStyle.fill
thus drawing a rectangle over the original rectangle instead of borders, I do seem to get the correct borders:
style
paint
PaintingStyle.fill
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) {
// rect = rect.deflate(borderWidth / 2.0);
Paint paint;
final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect);
paint = new Paint()
..color = Colors.red.withOpacity(0.25)
..style = PaintingStyle.fill
..strokeWidth = borderWidth;
canvas.drawRRect(borderRect, paint);
}
I'm still puzzled on how to do this...
2 Answers
2
You should use canvas.drawPath not drawRect
Paint paint = new Paint()
..color = borderColor
..style = PaintingStyle.stroke
..strokeWidth = borderWidth;
canvas.drawPath(getOuterPath(rect), paint);
also if you just want a border, its enough to use
@override
Path getInnerPath(Rect rect, {TextDirection textDirection}) {
return new Path()
..fillType = PathFillType.evenOdd
..addPath(getOuterPath(rect), Offset.zero);
}
I actually got a really nice solution with
drawRect
. I'm very busy atm and the code is too much of a mess to share rn, but I'll post it when I find the time to clean it!– Bram Vanbilsen
Jun 4 at 18:00
drawRect
@BramVanbilsen any update? Curious.
– seenickcode
Jul 11 at 13:09
You can use canvas.drawRRect
:
canvas.drawRRect
canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromLTWH(size.width / 2 - gap - smallMarkWidth - 15,gap * 8,gap + 70,gap * 5,),Radius.circular(15.0)),backgroundPaint);
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I did find a solution for this. My code is too much of a mess to post and I don't have the time to clean it atm. But I'll post it once I find the time!
– Bram Vanbilsen
Jun 4 at 18:01