likes
comments
collection
share

Flutter中使用canvas绘制贝塞尔曲线

作者站长头像
站长
· 阅读数 59

Flutter中使用canvas绘制贝塞尔曲线

贝塞尔曲线简介

贝塞尔曲线(Bézier curve)是一种通过给定的控制点来定义的数学曲线,广泛应用于计算机图形学、动画、几何建模等领域。贝塞尔曲线由法国工程师皮埃尔·贝塞尔(Pierre Bézier)在20世纪60年代为汽车设计而开发,后来被广泛应用于计算机图形学中。

在计算机图形学中,贝塞尔曲线通常用于绘制平滑的曲线和形状,如字体设计、动画路径、3D建模等。此外,贝塞尔曲线也是许多图形软件(如Adobe Illustrator、AutoCAD等)中常用的绘图工具。贝塞尔曲线有多种类型,包括:

  • 二阶贝塞尔曲线:由三个控制点定义,形状类似于抛物线。

  • 三阶贝塞尔曲线:由四个控制点定义,可以创建更复杂的形状。

  • 高阶贝塞尔曲线:由更多控制点定义,可以创建更复杂的曲线。

如下图中选中曲线可以理解为二阶贝塞尔曲线,1、3两点为端点,1、3端点之间的2称为控制点Flutter中使用canvas绘制贝塞尔曲线如下图中选中曲线可以理解为三阶贝塞尔曲线,1、4两点为端点,1、4端点之间的2、3称为控制点Flutter中使用canvas绘制贝塞尔曲线到这儿其实就可以知道计算机绘图中,大量使用了贝塞尔曲线。

一些与贝塞尔曲线有关的网站:

在线钢笔路径绘制:bezier.method.ac/

Flutter中使用canvas绘制贝塞尔曲线

贝塞尔曲线-数学表达式:www.desmos.com/calculator/…

Flutter中使用canvas绘制贝塞尔曲线

小结:贝塞尔曲线在计算机图形领域经常使用到,贝塞尔曲线可由数学表达式表达

Flutter中绘制

在UI开发中经常会遇到一些,使用常规内置基础控件实现不了的设计图,或者一些控件自定义度不够高,那么就可以考虑使用canvas利用贝塞尔曲线手动绘制形状。

Flutter中使用canvas绘制贝塞尔曲线例如上图中的底部导航栏中间有一个圆形凹槽,并且凹槽顶部两角为圆滑过度,使用常规的ClipPath路径剪裁并不好处理

Flutter中使用canvas绘制贝塞尔曲线

值得一提的是canvas绘制的原点是父布局的左上角,y轴向下为正数值,如下图所示

Flutter中使用canvas绘制贝塞尔曲线

在sketch、figma等绘图软件中的有标尺,其实就是绘制的x,y轴,原点同样为左上角x轴向右为正,y轴向下为正

Flutter中使用canvas绘制贝塞尔曲线

Flutter中使用canvas绘制贝塞尔曲线

双击路径选中点,就可看到每个点的x,y坐标,就可以使用canvas开始绘制了。在flutter使用CustomPaint控件,在CustomPainter中paint实现使用canvas具体绘制逻辑,其中常用的API有path.moveTo()移动画笔到某点,lineTo()连接到某点,quadraticBezierTo()二阶贝塞尔,cubicTo()三阶贝塞尔

二阶贝塞尔曲线(Quadratic Bézier Curve)

quadraticBezierTo() 方法用于绘制二阶贝塞尔曲线。它需要两个参数:控制点的坐标和结束点的坐标。二阶贝塞尔曲线由起始点、一个控制点和结束点组成。

void quadraticBezierTo(
  double x1, // 控制点的x坐标
  double y1, // 控制点的y坐标
  double x2, // 结束点的x坐标
  double y2, // 结束点的y坐标
)

三阶贝塞尔曲线(Cubic Bézier Curve)

cubicTo() 方法用于绘制三阶贝塞尔曲线。它需要四个参数:第一个控制点的坐标和第二个控制点的坐标,以及结束点的坐标。三阶贝塞尔曲线由起始点、两个控制点和结束点组成。

void cubicTo(
  double x1, // 第一个控制点的x坐标
  double y1, // 第一个控制点的y坐标
  double x2, // 第二个控制点的x坐标
  double y2, // 第二个控制点的y坐标
  double x3, // 结束点的x坐标
  double y3, // 结束点的y坐标
)

下面以带凹槽的导航栏为例,在Flutter中使用CustomPaint以及使用canvas自定义绘制实现

Flutter中使用canvas绘制贝塞尔曲线

CustomPaint(
  size: Size(375.w, 84.5.h),
  painter: NavPainter(),
  //foregroundPainter: NavPainter(),
),
class NavPainter extends CustomPainter {
        @override
        void paint(Canvas canvas, Size size) {
            var paint = Paint()
            ..color = Colors.white
            ..style = PaintingStyle.fill // 填充样式
            ..isAntiAlias = true; // 开启抗锯齿

            var path = Path();
            path.moveTo(0, 84.5.h);
            path.lineTo(0, 31.5.h);
            path.cubicTo(0, 14.38.h, 13.88.w, 0.5.h, 31.w, 0.5.h);
            path.lineTo(139.w, 0.5.h);
            path.quadraticBezierTo(149.5.w, 0.5.h, 149.5.w, 11.h);
            path.cubicTo(149.5.w, 31.99.h, 166.6.w, 49.h, 187.5.w, 49.h);
            path.cubicTo(208.4.w, 49.h, 225.5.w, 31.99.h, 225.5.w, 11.h);
            path.quadraticBezierTo(225.5.w, 0.5.h, 236.w, 0.5.h);
            path.lineTo(344.w, 0.5.h);
            path.cubicTo(361.12.w, 0.5.h, 375.w, 14.38.h, 375.w, 31.5.h);
            path.lineTo(375.w, 84.5.h);
            path.lineTo(0, 84.5.h);

            // 创建阴影用的Paint,设置阴影颜色和透明度
            final shadowPaint = Paint()
            ..color = const Color(0xFF000000).withOpacity(0.12)
            ..style = PaintingStyle.fill
            ..isAntiAlias = true
            ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 8); // 设置阴影的模糊度

            canvas.drawPath(path, shadowPaint);
            canvas.drawPath(path, paint);
    }
  
    @override
    bool shouldRepaint(CustomPainter oldDelegate) {
        return true;
    }
}

Flutter中使用canvas绘制贝塞尔曲线

在真机上的效果

小结:使用canvas结合贝塞尔曲线可以绘制出和UI还原度较高的图形,若绘制包含大量节点和曲线的复杂路径可能会消耗更多的资源。

转载自:https://juejin.cn/post/7368421971385040908
评论
请登录