12、Flutter组件装饰

组件装饰和视觉效果

类似于平时房子的装饰,要想把界面做得漂亮和酷炫就需要一些特殊操作,比如添加边框、增加透明度、做部分裁剪等。

Opacity(透明度处理)
DecoratedBox(装饰盒子)
Rotate(旋转盒子)
Clip(裁剪处理)
自定义画板案例

Opacity(透明度)

Opacity组件有一个opacity属性,能调整子组件的不透明度,使子控件部分透明,其中0.0表示完全透明,1.0表示完全不透明。

属性名 类型 说明
opacity double 不透明度值,值从0.0到1.0之间,0.0表示完全透明,1.0表示完全不透明
child Widget 组件的子组件,只能有一个子组件,子组件受不透明度属性影响

接下来编写一个例子,添加一个容器,外围用Opacity组件包装,不透明度值设置为0.3,容器添加纯黑色的底色。

import 'package:flutter/material.dart';
void main() => runApp(
  MaterialApp(
    title: 'Opacity不透明度',
    home: LayoutDemo(),
  )
);
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Opacity不透明度'),),
      body: Center(
        child: Opacity(
          opacity: 0.3,
          child: Container(
             250.0,
            height: 100.0,
            decoration: BoxDecoration(
              color: Colors.black,
            ),
            child: Text('不透明度为0.3', style: TextStyle(color: Colors.white, fontSize: 28.0),),
          ),
        ),
      ),
    );
  }
}

DecoratedBox(装饰盒子)

DecoratedBox可以从多方面进行装饰处理,比如颜色、形状、阴影、渐变及背景图片等。

它有一个非常重要的属性是decoration,类型为BoxDecoration。

属性名 类型 默认值 说明
shape BoxShape BoxShape.rectangle 形状取值
color Color 用来渲染容器的背景色
boxShadow List 阴影效果
gradient Gradient 渐变色取值:线性渐变、环形渐变
image DecorationImage 背景图片
border BoxBorder 边框样式
borderRadius BorderRadiusGeometry 边框的弧度

接下来编写几个例子来演示各种装饰的效果。

背景图效果

给容器添加背景图,只需要给image属性指定一个DecorationImage对象即可。它和Image的属性基本一致。

import 'package:flutter/material.dart';
void main() => runApp(
  MaterialApp(
    title: 'BoxDecration装饰盒子-背景图',
    home: LayoutDemo(),
  )
);
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('BoxDecration装饰盒子-背景图'), centerTitle: true,),
      body: Center(
        child: Container(
           300.0,
          height: 300.0,
          decoration: BoxDecoration(
            color: Colors.grey,
            image: DecorationImage(
              image: AssetImage('images/1.jpg'),
              fit: BoxFit.cover
            ),
          ),
        ),
      ),
    );
  }
}

边框圆角处理

给容器添加边框,既可以添加所有边框,也可以只加某一个边框。为了使容器显得平滑,可以添加borderRadius属性,值越大则弧度越大。

border: Border.all(color: Colors.grey, 4.0);

其中EdgeInsets支持多种自定义方法:

EdgeInsets.all()所有方向。
EdgeInsets.only(left, top, right, bottom)分别定义各个方向的边框。
EdgeInsets.symmetic(vertical, horizontal)自定义垂直、水平方向边框。
EdgeInsets.fromWindowPadding(ui.WindowPadding padding, double devicePixelRatio)根据机型屏幕尺寸定义。

在“背景图效果”的示例基础上,添加一个边框及圆角处理。完整代码如下:

import 'package:flutter/material.dart';
void main() => runApp(
  MaterialApp(
    title: 'BoxDecration装饰盒子-边框圆角',
    home: LayoutDemo(),
  )
);
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('BoxDecration装饰盒子-边框圆角'), centerTitle: true,),
      body: Center(
        child: Container(
           300.0,
          height: 300.0,
          decoration: BoxDecoration(
            color: Colors.grey,
            // 添加所有边框,颜色为灰色,宽度为4.0
            border: Border.all(color: Colors.grey,  4.0),
            // 添加边框弧度,这样会有一个圆角效果
            borderRadius: BorderRadius.circular(36.0),
            image: DecorationImage(
              image: AssetImage('images/1.jpg'),
              fit: BoxFit.cover
            ),
          ),
        ),
      ),
    );
  }
}

边框阴影处理

为容器边框加上阴影、会使得容器显得更有立体感,在DecratedBox组里添加boxShadow即可实现。

BoxShadow有几个重要属性如下所示:

color:阴影颜色
blurRadius:模糊值
spreadRadius:扩展阴影半径
offset:x和y方向偏移量

BoxShadow的使用如下代码所示:

boxShadow:<BoxShadow>[
    BoxShadow(
        color: Colors.grey,// 阴影颜色
        blurRadius: 8.0, // 模糊值
        spreadRadius: 8.0, // 拓展阴影半径
        offset: Offset(-1.0, 1.0), // x和y方向偏移量
    ),
],

编写一个例子,添加一个容器并加上BoxShadow处理。完整代码如下所示:

import 'package:flutter/material.dart';
void main() => runApp(
  MaterialApp(
    title: 'BoxDecration装饰盒子-边框阴影',
    home: LayoutDemo(),
  )
);
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('BoxDecration装饰盒子-边框阴影'), centerTitle: true,),
      body: Center(
        child: Container(
           300.0,
          height: 300.0,
          decoration: BoxDecoration(
            color: Colors.white,
            // 边框阴影效果
            boxShadow: [
              BoxShadow(
                color: Colors.grey, // 阴影颜色
                blurRadius: 8.0, // 模糊值
                spreadRadius: 8.0, // 扩展阴影半径
                offset: Offset(-1.0, 1.0), // x和y方向偏移量
              ),
            ],
          ),
          child: Text(
            'BoxShadow阴影效果',
            style: TextStyle(color: Colors.black, fontSize: 28.0),
          ),
        ),
      ),
    );
  }
}

渐变处理

渐变有两种形式,一种是LinearGradient线性渐变,另一种是RadialGradient环形渐变。它们有一个共性,需要一组数组数据来进行渲染界面。

LinearGradient线性渐变参数包括:

begin:起始偏移量。
end:终止偏移量。
colors:渐变颜色数据集。

LinearGradient的使用代码如下所示:

gradient: LinearGradient(
  begin: const FractionalOffset(0.5, 0.0), // 起始偏移量
  end: const FractionalOffset(1.0, 1.0), // 终止偏移量
  // 渐变颜色数据集
  colors: [
    Colors.red,
    Colors.green,
    Colors.blue,
    Colors.grey,
  ],
),

编写一个容器并添加线性渐变处理,代码如下:

import 'package:flutter/material.dart';
void main() => runApp(
  MaterialApp(
    title: 'LinearGradient线性渐变',
    home: LayoutDemo(),
  )
);
class LayoutDemo extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(title: Text('LinearGradient线性渐变'),),
        body: Center(
          child: DecoratedBox(
            decoration: BoxDecoration(
              gradient: LinearGradient(
                begin: const FractionalOffset(0.5, 0.0), // 起始偏移量
                end: const FractionalOffset(1.0, 1.0), // 终止偏移量
                // 渐变颜色数据集
                colors: [
                  Colors.red,
                  Colors.green,
                  Colors.blue,
                  Colors.grey,
                ],
              ),
            ),
            child: Container(
               280.0,
              height: 280.0,
              child: Center(
                child: Text('LinearGradient线性渐变', style: TextStyle(color: Colors.black, fontSize: 28.0),),
              ),
            ),
          ),
        ),
      );
  }
}

RadialGradient环形渐变参数包括:

center:中心点偏移量,即x和y方向偏移量。
radius:圆形半径。
colors:渐变颜色数据集。

RadialGradient的使用代码如下所示:

gradient: RadialGradient(
  center: const Alignment(-0.0, -0.0), // 中心点偏移量,x和y均为0.0表示在正中心位置
  radius: 0.50, // 圆形半径
  // 渐变颜色数据集
  colors: [
    Colors.red,
    Colors.green,
    Colors.blue,
    Colors.grey,
  ],
),

编写一个容器并添加环形渐变处理,代码如下:

import 'package:flutter/material.dart';
void main() => runApp(
    MaterialApp(
      title: 'RadialGradient环形渐变',
      home: LayoutDemo(),
    )
);
class LayoutDemo extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('RadialGradient环形渐变'),),
      body: Center(
        child: DecoratedBox(
          decoration: BoxDecoration(
            gradient: RadialGradient(
              center: const Alignment(-0.0, -0.0), // 中心点偏移量,x和y均为0.0表示在正中心位置
              radius: 0.50, // 圆形半径
              // 渐变颜色数据集
              colors: [
                Colors.red,
                Colors.green,
                Colors.blue,
                Colors.grey,
              ],
            ),
          ),
          child: Container(
             280.0,
            height: 280.0,
            child: Center(
              child: Text('RadialGradient环形渐变', style: TextStyle(color: Colors.black, fontSize: 28.0),),
            ),
          ),
        ),
      ),
    );
  }
}

RotatedBox(旋转盒子)

RotatedBox组件即为旋转组件,可以使child发生旋转,旋转的度数是90度的整数倍。

接下来编写示例添加一个文本,让它旋转3次,即旋转270度。完整代码如下:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'RotatedBox旋转盒子',
      home: Scaffold(
        appBar: AppBar(title: Text('RotatedBox旋转盒子', style: TextStyle(color: Colors.white),),),
        body: Center(
          child: RotatedBox(
            quarterTurns: 3, // 旋转次数,一次为90度
            child: Text('RotatedBox旋转盒子', style: TextStyle(fontSize: 28.0),),
          ),
        ),
      ),
    );
  }
}

Clip(裁剪处理)

Clip功能是把一个组件剪掉一部分。Flutter有多个组件可以完成此类功能,如下所示:

ClipOval:图形裁剪。
ClipRRect:圆形矩形裁剪。
ClipRect:矩形裁剪。
ClipPath:路径裁剪。

这几类裁剪组件都有两个共同属性如下所示:

属性名 类型 说明
clipper CustomClipper 裁剪路径,比如椭圆、矩形等。
clipBehavior Clip 裁剪方式

ClipOval圆形裁剪

圆形裁剪可以用来剪裁圆形头像,做一个类似Avatat的组件。示例代码如下:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ClipOval圆形裁剪',
      home: Scaffold(
        appBar: AppBar(title: Text('ClipOval圆形裁剪', style: TextStyle(color: Colors.white),),),
        body: Center(
          child: ClipOval(
            child: SizedBox(
               300.0,
              height: 300.0,
              child: Image.asset('images/1.jpg', fit: BoxFit.fill,),
            ),
          ),
        ),
      ),
    );
  }
}

ClipRRect圆形矩形裁剪

ClipRRect这个组件用borderRadius参数来控制角的位置大小。代码如下所示:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ClipRRect圆形矩形裁剪',
      home: Scaffold(
        appBar: AppBar(title: Text('ClipRRect圆形矩形裁剪', style: TextStyle(color: Colors.white),),),
        body: Center(
          child: ClipRRect(
            borderRadius: BorderRadius.all(Radius.circular(30.0)),// 圆角弧度,值越大弧度越大
            child: SizedBox(
               300.0,
              height: 300.0,
              child: Image.asset('images/1.jpg', fit: BoxFit.fill,),
            ),
          ),
        ),
      ),
    );
  }
}

ClipRect矩形裁剪

ClipRect这个组件需要自定义clipper属性才能使用,否则没有效果。自定义clipper需要继承CustomClipper类,并重写getClip及shouldReclip两个方法。

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ClipRect矩形裁剪',
      home: Scaffold(
        appBar: AppBar(title: Text('ClipRect矩形裁剪', style: TextStyle(color: Colors.white),),),
        body: Center(
          child: ClipRect(
            clipper: RectClipper(), // 指定自定义的clipper
            child: SizedBox(
               300.0,
              height: 300.0,
              child: Image.asset('images/1.jpg', fit: BoxFit.fill,),
            ),
          ),
        ),
      ),
    );
  }
}
// 自定义clipper,类型为Rect
class RectClipper extends CustomClipper<Rect> {
  // 重写获取裁剪范围
  @override
  Rect getClip(Size size) {
    return Rect.fromLTRB(100.0, 100.0, size.width - 100.0, size.height - 100.0);
  }
  // 重写是否重新裁剪
  @override
  bool shouldReclip(CustomClipper<Rect> oldClipper) {
    return true;
  }
}

ClipPath路径裁剪

ClipPath这个组件由于采用矢量路径path,所以可以把组件裁剪为任意类型的形状。比如三角形、矩形、星形及多边形等等。

自定义clipper需要继承CustomClipper类,并且需要重写getClip及shouldReclip两个方法。

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ClipPath路径裁剪',
      home: Scaffold(
        appBar: AppBar(title: Text('ClipPath路径裁剪', style: TextStyle(color: Colors.white),),),
        body: Center(
          child: ClipPath(
            clipper: TriangleCliper(), // 指定自定义的三角形clipper
            child: SizedBox(
               100.0,
              height: 100.0,
              child: Image.asset('images/1.jpg', fit: BoxFit.fill,),
            ),
          ),
        ),
      ),
    );
  }
}
// 自定义clipper,类型为Path
class TriangleCliper extends CustomClipper<Path> {
  // 重写获取裁剪范围
  @override
  Path getClip(Size size) {
    Path path = new Path();
    path.moveTo(50.0, 50.0); // 起始点
    path.lineTo(50.0, 10.0); // 终止点
    path.lineTo(100.0, 50.0); // 起始点(50, 10), 终止点
    path.close();
    return path;
  }
  // 重写是否重新裁剪
  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

自定义画板(案例)

自定义画板可以画任意图形,如点、线、路径、矩形、圆形以及添加图形。

  • 画布Canvas和画笔Paint

画布好比是教室里的黑板或者白板,画布是一个矩形区域,我们可以在上面任意涂鸦。

在画布Canvas上可以画点、线、路径、矩形、圆形以及添加图形。与画布Canvas相关的方法如下:

画直线:drawLine()
画圆:drawCircle()
画椭圆:drawOval()
画矩形:drawRect()
画点:drawPoint()
画圆弧:drawArc()

仅有画布还不行,还需要画笔,画笔Paint为绘制方法提供颜色及粗细等参数。

属性名 类型 默认值 说明
color Colors Colors.blueAccent 画笔颜色
strockCap StrokeCap StrokeCap.round 画笔笔触类型
isAntiAlias bool true 是否启动抗锯齿
blendMode BlendMode BlendMode.exclusion 颜色混合模式
style PaintingStyle PaintingStyle.fill 绘画样式,默认为填充
colorFilter ColorFilter ColorFilter.mode(Colors.blueAccent, BlendMode.exclusion) 颜色渲染模式,一般是矩阵效果来改变的,但是Flutter中只能使用颜色混合模式
maskFilter MaskFilter MaskFilter.blur(BlurStyle.inner, 3.0) 模糊遮罩效果
filterQuality FilterQuality FilterQuality.high 颜色渲染模式的质量
strokeWidth double 16.0 画笔的粗细

读懂这些参数后,实例化一支画笔即可,代码如下所示:

Paint paint= Paint() 
.. color= Colors.green // 画笔颜色
.. strokeCap = StrokeCap.round // 画笔笔触类型
.. isAntiAlias = true // 是否启动抗锯齿
.. blendMode = BlendMode.exclusion // 颜色混合模式
.. style= PaintingStyle.fill // 绘画风格,默认为填充
.. colorFilter = ColorFilter.mode(Colors.blueAccent, BlendMode.exclusion) // 颜色渲染模式
.. maskFilter = MaskFilter.blur(BlurStyle.inner, 3.0) // 模糊遮罩效果
.. filterQuality = FilterQuality.high // 渲染模式的质量
.. strokeWidth = 16.0 ; // 画笔的宽度

注意:实际使用中不需要传入这么多参数,一般传入画笔颜色、粗细及填充色即可。

  • 绘制直线

绘制直线需要调用Canvas的drawLine方法,传入起点及终点的坐标即可。

canvas.drawLine(Offset(20.0, 20.0), Offset(300.0, 20.0 ), _paint);

完整代码如下所示:

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.black
    ..strokeCap = StrokeCap.square
    ..isAntiAlias = true
    ..strokeWidth = 3.0
    ..style = PaintingStyle.stroke;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
    // 绘制直线
    canvas.drawLine(Offset(20.0, 20.0), Offset(300.0, 20.0), _paint);
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

绘制圆

绘制圆需要调用 Canvas drawCircle 方法,需要传入中心点的坐标、半径及画笔即可, 如下代码所示:

canvas.drawCircle(Offset(200.0, 150.0), 150.0, _paint);

其中画笔可以对应有填充色及没有填充色两种情况:

PaitingStyle.fill:填充绘制。
PaitingStyle.stroke:非填充绘制。

完整代码如下所示:

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.grey
    ..strokeCap = StrokeCap.square
    ..isAntiAlias = true
    ..strokeWidth = 3.0
    ..style = PaintingStyle.stroke;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
    // 绘制圆  
    canvas.drawCircle(Offset(200.0, 150.0), 150.0, _paint);
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

绘制椭圆

绘制椭圆需要调用Canvas的drawOval方法,同时需要使用一个矩形来确定绘制的范围,其中第一个参数为左上角坐标,第二个参数为右下角坐标。

Rect rect = Rect.fromPoints(Offset(80.0, 200.0), Offset(300.0, 300.0)); 
canvas.drawOval(rect, _paint);

创建Rect有多种方式:

fromPoints(Offset a, Offset b):使用左上和右下角坐标来确定内切矩形的大小和位置。
fromCircle({ Offset center, double radius}):使用圆的中心点坐标和半径确定外切矩形的大小和位置。
fromLTRB(double left , double top, double right , double bottom):使用矩形的上下左右的X、Y边界值来确定矩形的大小和位置。
fromLTWH(double left, double top, double width, double height):使用矩形左上角的X、Y坐标及矩形的宽高来确定矩形的大小和位置。

完整代码如下所示:

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.grey
    ..strokeCap = StrokeCap.square
    ..isAntiAlias = true
    ..strokeWidth = 3.0
    ..style = PaintingStyle.stroke;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
    // 绘制椭圆
    Rect rect = Rect.fromPoints(Offset(80.0, 200.0), Offset(300.0, 300.0));
    canvas.drawOval(rect, _paint);
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

绘制圆角矩形

绘制圆角矩形需要调用Canvas的drawRRect方法。

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.grey
    ..strokeCap = StrokeCap.square
    ..isAntiAlias = true
    ..strokeWidth = 3.0
    ..style = PaintingStyle.stroke;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
    // 中心点坐标为200,200 边长为100
    Rect rect = Rect.fromCircle(center: Offset(200.0, 200.0), radius: 100.0);
    // 根据矩形创建一个角度为20的圆角矩形
    RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(20.0));
    // 开始绘制圆角矩形
    canvas.drawRRect(rrect, _paint);
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

绘制嵌套矩形

绘制嵌套矩形需要调用 Canvas的drawDRRect 方法。函数中的这个D就是 Doubl意思, 也就是可以绘制两个矩形。

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.grey
    ..strokeCap = StrokeCap.square
    ..isAntiAlias = true
    ..strokeWidth = 3.0
    ..style = PaintingStyle.stroke;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
     // 初始化两个矩形
    Rect rect1 = Rect.fromCircle(center: Offset(150.0, 150.0), radius: 80.0);
    Rect rect2 = Rect.fromCircle(center: Offset(150.0, 150.0), radius: 40.0);
    // 将两个矩形转化成圆角矩形
    RRect outer = RRect.fromRectAndRadius(rect1, Radius.circular(20.0));
    RRect inner = RRect.fromRectAndRadius(rect2, Radius.circular(10.0));
    canvas.drawDRRect(outer, inner, _paint);
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

绘制多个点

绘制多个点需要调用Canvas的drawPoints方法。传入的参数PointMode的枚举类型有三个,points(点)、lines(隔点连接线)及polygon(相邻连接线)。

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.grey
    ..strokeCap = StrokeCap.square
    ..isAntiAlias = true
    ..strokeWidth = 20.0
    ..style = PaintingStyle.fill;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawPoints(
      // PointMode的枚举类型有三个:points点、lines隔点连接线、polygon相邻连接线
      PointMode.points,
      [
        Offset(50.0, 60.0),
        Offset(40.0, 90.0),
        Offset(100.0, 100.0),
        Offset(300.0, 350.0),
        Offset(400.0, 80.0),
        Offset(200.0, 200.0),
      ],
      _paint..color = Colors.grey
    );
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

PointMode.lines图形变为隔点连接线样式,PointMode.polygon图形变为相邻连接线样式。

绘制圆弧

绘制圆弧需要调用Canvas的drawArc方法。需要传入绘制区域、弧度及画笔参数。

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.grey
    ..strokeCap = StrokeCap.round
    ..isAntiAlias = true
    ..strokeWidth = 2.0
    ..style = PaintingStyle.stroke;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
    // 绘制圆弧
    const PI = 3.1415926;
    // 定义矩形
    Rect rect1 = Rect.fromCircle(center: Offset(100.0, 0.0), radius: 100.0);
    // 画1/2PI弧度的圆弧
    canvas.drawArc(rect1, 0.0, PI / 2, true, _paint);
    // 画PI弧度的圆弧
    Rect rect2 = Rect.fromCircle(center: Offset(200.0, 150.0), radius: 100.0);
    canvas.drawArc(rect2, 0.0, PI, true, _paint);
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

绘制路径Path

使用Canvas的drawPath方法理论上可以绘制任意矢量图,Path的主要方法如下所示:

moveTo:将路径起始点移动到指定位置。
lineTo:从当前位置连接指定点。
arcTo:曲线。
conicTo:贝塞尔曲线。
close:关闭路径,连接路径的起始点。

调用Canvas的drawPath方法绘制一个任意图形,完整代码如下所示:

// 继承自CustomPainter并且实现paint和shouldRepaint方法
class LinePainter extends CustomPainter {
   // 定义画笔
  Paint _paint = new Paint()
    ..color = Colors.grey
    ..strokeCap = StrokeCap.round
    ..isAntiAlias = true
    ..strokeWidth = 2.0
    ..style = PaintingStyle.stroke;
  // 重写绘制内容的方法
  @override
  void paint(Canvas canvas, Size size) {
     // 新建一个path移动到一个位置,然后画各种线
    Path path = new Path()..moveTo(100.0, 100.0);
    path.lineTo(200.0, 300.0);
    path.lineTo(150.0, 250.0);
    path.lineTo(150.0, 500.0);
    canvas.drawPath(path, _paint);
  }
  // 重写是否需要重绘的
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}
原文地址:https://www.cnblogs.com/pengjingya/p/14929307.html