简体   繁体   English

在Flutter中用矩形绘制贝塞尔曲线

[英]Draw Bezier curve with rectangle in Flutter

I'm starting with Flutter and have to design a UI that looks like我从Flutter开始,必须设计一个看起来像

在此处输入图像描述

But with icon button at the center of the Bezier curve.但是在贝塞尔曲线的中心有图标按钮。

What I tried is我尝试的是

class HeaderPainter extends CustomPainter {
  HeaderPainter({
    @required this.color,
    @required this.avatarRadius
  });

  final Color color;
  final double avatarRadius;

  @override
  void paint(Canvas canvas, Size size) {
    final shapeBounds = Rect.fromLTRB(0, 0, size.width, size.height - avatarRadius);
    final centerAvatar = Offset(shapeBounds.center.dx, shapeBounds.bottom);
    final avatarBounds = Rect.fromCircle(center: centerAvatar, radius: avatarRadius).inflate(3);
    _drawBackground(canvas, shapeBounds, avatarBounds);
  }

  @override
  bool shouldRepaint(HeaderPainter oldDelegate) {
    return color != oldDelegate.color;
  }

  void _drawBackground(Canvas canvas, Rect shapeBounds, Rect avatarBounds) {
    final paint = Paint()..color = color;

    final backgroundPath = Path()
      ..moveTo(shapeBounds.left, shapeBounds.top)
      ..lineTo(shapeBounds.bottomLeft.dx, shapeBounds.bottomLeft.dy)
      ..arcTo(avatarBounds, -pi, pi, false)
      ..lineTo(shapeBounds.bottomRight.dx, shapeBounds.bottomRight.dy)
      ..lineTo(shapeBounds.topRight.dx, shapeBounds.topRight.dy)
      ..lineTo(0.0, shapeBounds.height - 100)
      ..quadraticBezierTo(
          shapeBounds.width / 4, shapeBounds.height,
          shapeBounds.width / 2, shapeBounds.height
      )
      ..quadraticBezierTo(
          shapeBounds.width - shapeBounds.width / 4, shapeBounds.height,
          shapeBounds.width, shapeBounds.height - 100
      )
      ..lineTo(shapeBounds.width, 0.0)
      ..close();

    canvas.drawPath(backgroundPath, paint);
  }
}

And the outcome is结果是

在此处输入图像描述

How can I get the bezier curve with the rectangle?如何获得矩形的贝塞尔曲线?

Edit 2: The HeaderPainter is used like编辑 2: HeaderPainter 的使用方式如下

@override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Container(
          child: CustomPaint(
            size: Size.fromHeight(400.0),
            painter: HeaderPainter(
              color: Colors.red,
              avatarRadius: avatarRadius
            ),
          ),
        ),
        Positioned(
          left: 0,
          right: 0,
          bottom: titleBottomMargin,
          child: Column(
            children: <Widget>[
              Text('Hello World', style: TextStyle(fontWeight: FontWeight.bold),),
            ],
          ),
        ),
        Align(
          alignment: Alignment.bottomCenter,
          child: CircleAvatar(
            radius: avatarRadius,
            backgroundColor: Colors.green,
            child: IconButton(icon: Icon(Icons.message), onPressed: _onAddMessageButtonClick,),
          ),
        )
      ],
    );
  }

Got it solved using ClipPath and CustomClipper .使用ClipPathCustomClipper解决了这个问题。

The updated build() method is更新的build()方法是

@override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Container(
          child: ClipPath(
            clipper: HeaderClipper(avatarRadius: avatarRadius),
            child: CustomPaint(
              size: Size.fromHeight(400.0),
              painter: HeaderPainter(
                color: Colors.green,
                avatarRadius: avatarRadius
              ),
            ),
          ),
        ),
        ...

and HeaderClipperHeaderClipper

class HeaderClipper extends CustomClipper<Path> {
  HeaderClipper({
    @required this.avatarRadius
  });

  final avatarRadius;

  @override
  getClip(Size size) {
    final path = Path()
      ..lineTo(0.0, size.height - 100)
      ..quadraticBezierTo(
          size.width / 4, (size.height - avatarRadius),
          size.width / 2, (size.height - avatarRadius)
      )
      ..quadraticBezierTo(
          size.width - (size.width / 4), (size.height - avatarRadius),
          size.width, size.height - 100
      )
      ..lineTo(size.width, 0.0)
      ..close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper oldClipper) {
    return false;
  }
}

The final output is最终的 output 是

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM