Reputation: 170
I'm trying to add border radius to my custom shaped widget using Custom Paint, but I don't know how to add rounded edges to the custom shape.
I achieved the shape, but not the rounded edges.
Below is the code for the custom paint. How can I add border radius to the edges.
``
class RPSCustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint0 = Paint()
..color = const Color.fromARGB(255, 33, 150, 243)
..style = PaintingStyle.stroke
..strokeWidth = 1.4900000095367432;
Path path0 = Path();
path0.moveTo(3.03, 197.85);
path0.quadraticBezierTo(0.87, 47.28, 1.9, 1.36);
path0.lineTo(207.0, 2.0);
path0.lineTo(170.24, 197.9);
path0.quadraticBezierTo(16.26, 197.13, 3.03, 197.85);
canvas.drawPath(path0, paint0);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
``
Upvotes: 2
Views: 1420
Reputation: 406
I followed this answer and after some tweaks this is what we have:
Radius 10:
Radius 30:
Radius 90:
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Application',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: Padding(
padding: const EdgeInsets.all(40),
child: CustomPaint(
painter: RPSCustomPainter(borderRadius: 90),
child: Container(),
),
));
}
}
class RPSCustomPainter extends CustomPainter {
RPSCustomPainter({this.borderRadius = 10});
final double borderRadius;
@override
void paint(Canvas canvas, Size size) {
Paint paint0 = Paint()
..color = const Color.fromARGB(255, 33, 150, 243)
..style = PaintingStyle.stroke
..strokeWidth = 1.4900000095367432;
final points = [
const Offset(3.03, 197.9),
const Offset(1.9, 1.36),
const Offset(207.0, 2.0),
const Offset(170.24, 197.9),
];
final (lines, arcs) = getLinesAndArcs(points, borderRadius: borderRadius);
for (var i = 0; i < lines.length; i++) {
final line = lines[i];
final arc = arcs[i];
TextSpan span = TextSpan(
style: TextStyle(color: Colors.blue[800]),
text:
'${i.toString()}\nsweepAngle: ${arc.sweepAngle.toDegrees().toStringAsFixed(2)}\nstartAngle: ${arc.startAngle.toDegrees().toStringAsFixed(2)}\nendAngle: ${arc.endAngle.toDegrees().toStringAsFixed(2)}');
TextPainter tp = TextPainter(
text: span,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr);
tp.layout();
tp.paint(canvas, points[i]);
canvas.drawPoints(
PointMode.points,
[...points, line.end, line.start, arc.center],
Paint()
..strokeWidth = 5
..strokeCap = StrokeCap.round
..color = Colors.green);
canvas.drawLine(line.start, line.end, paint0);
canvas.drawArc(Rect.fromCircle(center: arc.center, radius: arc.radius),
arc.startAngle, arc.sweepAngle, false, paint0);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
double getLength(double dx, double dy) {
return math.sqrt(dx * dx + dy * dy);
}
List<List<Offset>> getVerticeTriplets(List<Offset> points) {
final triplets = <List<Offset>>[];
for (var i = 0; i < points.length; i += 1) {
final triplet = <Offset>[];
for (var j = 0; j < 3; j++) {
triplet.add(points[(i + j) % points.length]);
}
triplets.add(triplet);
}
return triplets;
}
(List<Line>, List<Arc>) getLinesAndArcs(
List<Offset> points, {
double borderRadius = 10,
}) {
var radius = borderRadius;
final starts = <Offset>[];
final ends = <Offset>[];
final arcs = <Arc>[];
final triplets = getVerticeTriplets(points);
for (var i = 0; i < triplets.length; i++) {
final [p1, angularPoint, p2] = triplets[i];
//Vector 1
final dx1 = angularPoint.dx - p1.dx;
final dy1 = angularPoint.dy - p1.dy;
//Vector 2
final dx2 = angularPoint.dx - p2.dx;
final dy2 = angularPoint.dy - p2.dy;
//Angle between vector 1 and vector 2 divided by 2
final angle = (math.atan2(dy1, dx1) - math.atan2(dy2, dx2)) / 2;
// The length of segment between angular point and the
// points of intersection with the circle of a given radius
final tan = math.tan(angle).abs();
var segment = radius / tan;
//Check the segment
final length1 = getLength(dx1, dy1);
final length2 = getLength(dx2, dy2);
final length = math.min(length1, length2);
if (segment > length) {
segment = length;
radius = (length * tan);
}
// Points of intersection are calculated by the proportion between
// the coordinates of the vector, length of vector and the length of the segment.
var p1Cross =
getProportionPoint(angularPoint, segment, length1, dx1, dy1);
ends.add(p1Cross);
var p2Cross =
getProportionPoint(angularPoint, segment, length2, dx2, dy2);
starts.add(p2Cross);
// Calculation of the coordinates of the circle
// center by the addition of angular vectors.
final dx = angularPoint.dx * 2 - p1Cross.dx - p2Cross.dx;
final dy = angularPoint.dy * 2 - p1Cross.dy - p2Cross.dy;
final L = getLength(dx, dy);
final d = getLength(segment, radius);
final circlePoint = getProportionPoint(angularPoint, d, L, dx, dy);
//StartAngle and EndAngle of arc
var startAngle =
math.atan2(p1Cross.dy - circlePoint.dy, p1Cross.dx - circlePoint.dx);
final endAngle =
math.atan2(p2Cross.dy - circlePoint.dy, p2Cross.dx - circlePoint.dx);
//Sweep angle
var sweepAngle = endAngle - startAngle;
//Some additional checks
if (sweepAngle < 0) {
startAngle = endAngle;
sweepAngle = -sweepAngle;
}
if (sweepAngle > math.pi) sweepAngle = math.pi - sweepAngle;
arcs.add(
Arc(
startAngle: startAngle,
sweepAngle: sweepAngle,
endAngle: endAngle,
center: Offset(circlePoint.dx, circlePoint.dy),
radius: radius,
),
);
}
final lines = <Line>[];
final shiftedStarts = [
starts.last,
...starts.sublist(0, starts.length - 1)
];
for (var i = 0; i < ends.length; i++) {
lines.add(Line(start: shiftedStarts[i], end: ends[i]));
}
return (lines, [arcs.last, ...arcs.sublist(0, arcs.length - 1)]);
}
Offset getProportionPoint(
Offset point, double segment, double length, double dx, double dy) {
double factor = segment / length;
return Offset((point.dx - dx * factor), (point.dy - dy * factor));
}
}
class Arc {
const Arc({
required this.startAngle,
required this.sweepAngle,
required this.center,
required this.radius,
required this.endAngle,
});
final double startAngle;
final double endAngle;
final double sweepAngle;
final Offset center;
final double radius;
}
class Line {
const Line({
required this.start,
required this.end,
});
final Offset start;
final Offset end;
}
extension on double {
double toDegrees() => this * 180 / math.pi;
}
Upvotes: 4
Reputation: 9206
you can use drawRRect()
to draw the border radius for corners of your shape.
canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromLTWH(size.width / 2 - gap - smallMarkWidth - 15,gap * 8,gap + 70,gap * 5,),Radius.circular(15.0)),backgroundPaint);
Upvotes: 1