Flutter 35: 图解自定义 View 之 Canvas (二)

简介: 0 基础学习 Flutter,第三十五步:自定义 View 第三节~

      小菜前几天整理了以下 Canvas 的部分方法,今天小菜继续学习 Canvas 第二部分。

drawXXX

drawShadow 绘制阴影

      drawShadow 用于绘制阴影,第一个参数时绘制一个图形 Path,第二个是设置阴影颜色,第三个为阴影范围,最后一个阴影范围是否填充满;

canvas.drawShadow(
    Path()
      ..moveTo(30.0, 30.0)..lineTo(120.0, 30.0)
      ..lineTo(120.0, 60.0)..lineTo(30.0, 60.0)
      ..close(),
    Colors.blue, 3, false);
canvas.drawShadow(
    Path()
      ..moveTo(30.0, 90.0)..lineTo(120.0, 90.0)
      ..lineTo(120.0, 120.0)..lineTo(30.0, 120.0),
    Colors.blue, 10, false);
canvas.drawShadow(
    Path()
      ..moveTo(30.0, 150.0)..lineTo(120.0, 150.0)
      ..lineTo(120.0, 180.0)..lineTo(30.0, 180.0)
      ..close(),
    Colors.blue, 3, true);
canvas.drawPath(
    Path()
      ..moveTo(30.0, 210.0)..lineTo(120.0, 210.0)
      ..lineTo(120.0, 240.0)..lineTo(30.0, 240.0),
    Paint()..color = Colors.blue..strokeWidth = 2..style = PaintingStyle.stroke);

drawImage 绘制图片

      drawImage 用于绘制图片,绘制图片是重点,此时的 Image 并非日常所用的图片加载,而是用的 dart.ui 类中的 ui.Image 并转换成字节流 ImageStream 方式传递,包括本地图片或网络图片

// 获取图片 本地为false 网络为true
Future<ui.Image> _loadImage(var path, bool isUrl) async {
  ImageStream stream;
  if (isUrl) {
    stream = NetworkImage(path).resolve(ImageConfiguration.empty);
  } else {
    stream =
        AssetImage(path, bundle: rootBundle).resolve(ImageConfiguration.empty);
  }
  Completer<ui.Image> completer = Completer<ui.Image>();
  void listener(ImageInfo frame, bool synchronousCall) {
    final ui.Image image = frame.image;
    completer.complete(image);
    stream.removeListener(listener);
  }

  stream.addListener(listener);
  return completer.future;
}

// 加载图片
_prepareImg() {
  _loadImage('images/icon_hzw02.jpg', false).then((image1) {
    _image1 = image1;
  }).whenComplete(() {
    _loadImage('https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=703702342,1604162245&fm=26&gp=0.jpg', true)
        .then((image2) {
      _image2 = image2;
    }).whenComplete(() {
      _prepDone = true;
      if (this.mounted) {
        setState(() {});
      }
    });
  });
}

canvas.drawImage(this.image, ui.Offset(120.0, 540.0), Paint());
canvas.drawImage(this.image2, ui.Offset(60.0, 60.0), Paint());

Tips:

      小菜在尝试过程中总是加载失败,后来理解为绘制过程需要时间,可以通过 setState(() {});whenComplete 判断状态后进行刷新,这种方式并非最佳,希望有更好方式的朋友多指导。

drawImageRect 绘制矩形图片

      drawImageRect 除了可以正常绘制图片之外,还可以绘制图片部分内容,如下:第一个参数为 ui.Image,第二个参数为需要原图绘制矩形范围,第三个参数为本次绘制矩形范围,最后一个为画笔;

      小菜绘制原图与部分图进行对比,drawImageRect 绘制的原图粉色圈出的范围;且 drawImageRect 效率更好,推荐使用;

canvas.drawImage(this.image, ui.Offset(60.0, 540.0), Paint());
canvas.drawImageRect(
    this.image,
    Rect.fromLTWH(0, 0, 60, 60),
    Rect.fromLTWH(60, 60, image.width.toDouble(), image.height.toDouble()),
    Paint());

drawImageNine 绘制九图

      drawImageNine 同样用来绘制图片,与原图绘制方式不同在于,drawImageNine 中第二个参数矩形变长延伸将原图分割为九部分,划为中心区域,第三个参数矩形即绘制整体矩形范围,包括四个顶点位置;小菜绘制原图与部分图进行对比,drawImageNine 绘制的原图绿色圈出的范围,小菜感觉类似于裁剪了原图;

canvas.drawImage(this.image, ui.Offset(60.0, 540.0), Paint());
canvas.drawImageNine(
    this.image,
    Rect.fromLTWH(0, 0, 120, 60),
    Rect.fromLTWH(
        60, 1020, image.width.toDouble() - 120, image.height.toDouble()),
    Paint());

drawParagraph 绘制文字段落

      小菜以前认为 Canvas 不支持绘制文字,现在学习了 drawParagraph 完全可以绘制文字效果与 TextPainter 效果相同;

      文字段落 Paragraphdart.ui 中的类,用构造器方式进行内容绑定;ParagraphStyle 用来设置文字的样式属性,包括文字位置/方向/字体粗细/文字样式/行数等;其中 ellipsis 用来设置内容超出范围截取时最后展示内容,可随意编辑;

ParagraphBuilder pb = ParagraphBuilder(ParagraphStyle(
  textAlign: TextAlign.center,
  fontWeight: FontWeight.w600,
  fontStyle: FontStyle.normal,
  fontSize: 18,
))
  ..pushStyle(ui.TextStyle(color: Colors.blue))
  ..addText(
      'Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。');
ParagraphConstraints pc = ParagraphConstraints(width: Screen.width - 60);
Paragraph paragraph = pb.build()..layout(pc);
canvas.drawParagraph(paragraph, Offset(30, 30));

pb = ParagraphBuilder(ParagraphStyle(
  fontStyle: FontStyle.normal,
  fontWeight: FontWeight.w300,
  fontSize: 18,
))
  ..pushStyle(ui.TextStyle(color: Colors.red))
  ..addText(
      'Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。');
pc = ParagraphConstraints(width: Screen.width - 60);
paragraph = pb.build()..layout(pc);
canvas.drawParagraph(paragraph, Offset(30, 180));

pb = ParagraphBuilder(ParagraphStyle(
  fontStyle: FontStyle.normal,
  fontSize: 18,
  maxLines: 3,
  ellipsis: '...',
))
  ..pushStyle(ui.TextStyle(color: Colors.green))
  ..addText(
      'Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。');
pc = ParagraphConstraints(width: Screen.width - 60);
paragraph = pb.build()..layout(pc);
canvas.drawParagraph(paragraph, Offset(30, 340));

clipXXX

      以上介绍的都是绘制方法,接下来小菜简单介绍几种裁剪方法。

clipRect 裁剪矩形

      clipRect 可以在规定的矩形内进行绘制,超出范围不绘制;

canvas.clipRect(Rect.fromLTWH(30, 1200, Screen.width / 0.3 - 60, 300),
    doAntiAlias: false);
canvas.drawImage(this.image, ui.Offset(260, 1200), Paint());

clipRRect 裁剪圆角矩形

      clipRRect 可以在规定的圆角矩形内进行绘制,超出范围不绘制;

canvas.clipRRect(
    RRect.fromRectXY(
        Rect.fromLTWH(300, 1600, image.width - 60.0, 300), 20, 20),
    doAntiAlias: false);
canvas.drawImage(this.image, ui.Offset(260, 1200), Paint());

clipPath 裁剪由线围成区域

      clipPath 可以在规定的点连线范围内进行绘制,默认终点与始点连接,当然可以绘制圆或贝塞尔曲线等,超出范围不绘制;

canvas.clipPath(Path()
  ..moveTo(300, 100)..lineTo(900, 100)
  ..lineTo(800, 600)..lineTo(400, 600));
canvas.drawImage(this.image, ui.Offset(260, 90), Paint());


      Canvas 真的非常强大,还有很多研究不透彻的地方,小菜还在不断学习,有错误的地方烦请多多指点!

目录
相关文章
|
8月前
|
Dart 前端开发
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
248 75
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
8月前
|
Dart 前端开发 容器
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
214 18
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
10月前
|
UED 开发者 容器
Flutter&鸿蒙next 的 Sliver 实现自定义滚动效果
Flutter 提供了强大的滚动组件,如 ListView 和 GridView,但当需要更复杂的滚动效果时,Sliver 组件是一个强大的工具。本文介绍了如何使用 Sliver 实现自定义滚动效果,包括 SliverAppBar、SliverList 等常用组件的使用方法,以及通过 CustomScrollView 组合多个 Sliver 组件实现复杂布局的示例。通过具体代码示例,展示了如何实现带有可伸缩 AppBar 和可滚动列表的页面。
350 1
|
10月前
Flutter 自定义组件继承与调用的高级使用方式
本文深入探讨了 Flutter 中自定义组件的高级使用方式,包括创建基本自定义组件、继承现有组件、使用 Mixins 和组合模式等。通过这些方法,您可以构建灵活、可重用且易于维护的 UI 组件,从而提升开发效率和代码质量。
293 1
|
10月前
|
前端开发 开发者
深入探索 Flutter 鸿蒙版的画笔使用与高级自定义动画
本文深入探讨了 Flutter 中的绘图功能,重点介绍了 CustomPainter 和 Canvas 的使用方法。通过示例代码,详细讲解了如何绘制自定义图形、设置 Paint 对象的属性以及实现高级自定义动画。内容涵盖基本绘图、动画基础、渐变动画和路径动画,帮助读者掌握 Flutter 绘图与动画的核心技巧。
243 1
|
10月前
|
Dart UED 开发者
Flutter&鸿蒙next中的按钮封装:自定义样式与交互
在Flutter应用开发中,按钮是用户界面的重要组成部分。Flutter提供了多种内置按钮组件,但有时这些样式无法满足特定设计需求。因此,封装一个自定义按钮组件变得尤为重要。自定义按钮组件可以确保应用中所有按钮的一致性、可维护性和可扩展性,同时提供更高的灵活性,支持自定义颜色、形状和点击事件。本文介绍了如何创建一个名为CustomButton的自定义按钮组件,并详细说明了其样式、形状、颜色和点击事件的处理方法。
219 1
|
10月前
|
Dart 搜索推荐 API
Flutter & 鸿蒙next版本:自定义对话框与表单验证的动态反馈与错误处理
在现代移动应用开发中,用户体验至关重要。本文探讨了如何在 Flutter 与鸿蒙操作系统(HarmonyOS)中创建自定义对话框,并结合表单验证实现动态反馈与错误处理,提升用户体验。通过自定义对话框和表单验证,开发者可以提供更加丰富和友好的交互体验,同时利用鸿蒙next版本拓展应用的受众范围。
221 1
|
前端开发 vr&ar 容器
Flutter 115: 图解自定义 View 之 Canvas (四) drawParagraph
0 基础学习 Flutter,第一百一十五节:自定义 Canvas 第四节,文本绘制小结!
731 0
Flutter 115: 图解自定义 View 之 Canvas (四) drawParagraph
|
前端开发 Android开发 存储
Flutter 36: 图解自定义 View 之 Canvas (三)
0 基础学习 Flutter,第三十六步:自定义 View 第四节~
2222 0
|
前端开发
Flutter 34: 图解自定义 View 之 Canvas (一)
0 基础学习 Flutter,第三十四步:自定义 View 第二节~
2730 0