问题
I want to build a layout like this
Where the two external elements are buttons, while the inner one is a TextField.
How can I create a layout like this in Flutter?
My idea was to use absolute positions to align the left side of each element and to use elevation to handle overlapping but I'm not sure it's the best way and I don't know how to create the buttons.
回答1:
I would use a CustomPainter class, with which you build the buttons. Then you use the RawMaterialButton and CustomPaint widget to use it in your application. To position and overlap the elements i would use the Stack widget.
Attached you see an example of your outer right button:
...
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:
I've found another, more elegant, solution to solve this. Instead of using a CustomPainter you can use a CustomClipper with the ClipPath widget. Important is, that the ClipPath and the color of the button is outside the RawMaterialButton, only then, the ripple effect on tapping the button is the same shape as the button itself:
...
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;
}
来源:https://stackoverflow.com/questions/60833862/create-buttons-with-negative-border-radius-and-align-them-in-flutter