Create buttons with negative border radius and align them in Flutter

我的梦境 提交于 2021-02-08 06:55:43

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!