【问题标题】:Draw Bezier curve with rectangle in Flutter在 Flutter 中用矩形绘制贝塞尔曲线
【发布时间】:2020-06-28 19:04:51
【问题描述】:

我从 Flutter 开始,必须设计一个看起来像

的 UI

但是在贝塞尔曲线的中心有一个图标按钮。

我尝试的是

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);
  }
}

结果是

如何获得带有矩形的贝塞尔曲线?

编辑 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,),
          ),
        )
      ],
    );
  }

【问题讨论】:

  • 把它们放在列中
  • 只需制作 2 个不同尺寸的盒子并将它们放在一列中

标签: flutter flutter-layout bezier


【解决方案1】:

使用ClipPathCustomClipper 解决了。

更新后的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
              ),
            ),
          ),
        ),
        ...

HeaderClipper

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;
  }
}

最终的输出是

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-26
    • 2013-08-21
    • 2017-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    相关资源
    最近更新 更多