我会用一个CustomPainter
类,您可以用它来构建按钮。然后你使用RawMaterialButton
and CustomPaint
小部件以在您的应用程序中使用它。为了定位和重叠元素,我将使用 Stack 小部件。
您可以在附件中看到外部右侧按钮的示例:
...
body: Center(
child: RawMaterialButton(
onPressed: () {},
child: CustomPaint(
painter: ButtonShape(
strokeColor: Colors.blue,
strokeWidth: 1,
paintingStyle: PaintingStyle.fill,
),
child: Container(
child: Center(
child: Text('+', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 36)),
),
height: 50,
width: 150,
),
),
),
),
...
class ButtonShape extends CustomPainter {
final Color strokeColor;
final PaintingStyle paintingStyle;
final double strokeWidth;
ButtonShape({this.strokeColor = Colors.black, this.strokeWidth = 3, this.paintingStyle = PaintingStyle.stroke});
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = strokeColor
..strokeWidth = strokeWidth
..style = paintingStyle;
canvas.drawPath(shapePath(size.width, size.height), paint);
}
Path shapePath(double x, double y) {
return Path()
..moveTo(0, 0)
..cubicTo(x/2, 0, x/2, y, 0, y)
..cubicTo(x, y, x, 0, 0, 0);
}
@override
bool shouldRepaint(ButtonShape oldDelegate) {
return oldDelegate.strokeColor != strokeColor ||
oldDelegate.paintingStyle != paintingStyle ||
oldDelegate.strokeWidth != strokeWidth;
}
}
Update:我找到了另一个更优雅的解决方案来解决这个问题。而不是使用CustomPainter
你可以使用CustomClipper
与ClipPath
小部件。重要的是,ClipPath
和color
按钮的外面RawMaterialButton
,只有这样,点击按钮时的涟漪效果才与按钮本身的形状相同:
...
body Center(
child: ClipPath(
clipper: ButtonClipper(),
child: Container(
color: Colors.blue,
child: RawMaterialButton(
onPressed: () {},
child: Container(
height: 50,
width: 150,
child: Center(
child: Text('+', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 36)),
),
),
),
),
),
),
...
class ButtonClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
final path = Path();
path.moveTo(0, 0);
path.cubicTo(size.width / 2, 0, size.width / 2, size.height, 0, size.height);
path.cubicTo(size.width, size.height, size.width, 0, 0, 0);
path.close();
return path;
}
@override
bool shouldReclip(ButtonClipper oldClipper) => false;
}