Flutter 115: 图解自定义 View 之 Canvas (四) drawParagraph

简介: 0 基础学习 Flutter,第一百一十五节:自定义 Canvas 第四节,文本绘制小结!

    小菜在前两节通过 Canvas 绘制图形时涉及到部分文字绘制,之前只是简单的尝试,有很多未注意到的地方;小菜今天尝试全面的学习尝试一下;通过 Canvas 绘制文字时使用的属性效果与直接使用 TextView 对应基本一致;

Canvas.drawParagraph

  1. 新建一个 ParagraphBuilder 段落构造器;
  2. 在构造器中添加文本的基本信息,包括 ParagraphStyle 文本属性等;
  3. 通过 ParagraphConstraints 约束段落容器宽度;
  4. 通过 layout 计算段落中每个字形的大小和位置;
  5. 通过 Canvas.drawParagraph 进行文字绘制;
// 1-2 段落构造器并添加文本信息
ParagraphBuilder _pb = ParagraphBuilder(
    ParagraphStyle(fontWeight: FontWeight.normal, fontSize: 17))
  ..pushStyle(ui.TextStyle(color: Colors.blue))
  ..addText(str);
// 3 设置段落容器宽度
ParagraphConstraints pc = ParagraphConstraints(width: size.width - 100);
// 4 计算文本位置及尺寸
Paragraph paragraph = _pb.build()..layout(pc);
// 5 文本绘制
canvas.drawParagraph(paragraph, Offset(50.0, 50.0));

ParagraphStyle

1. fontSize

    fontSize 为字体绘制时字号,以逻辑像素为单位;

fontSize: 14.0 + (i + 1)

2. fontWeight

    fontWeight 用于绘制文本的字形的粗细,从 w100 -> w900 逐级变粗;默认是 w400

fontWeight: FontWeight.values[i + 1],

3. fontStyle

    fontStyle 为字体样式,是否为 normal 正规或 italic 斜体;

fontStyle: (i % 2 == 0) ? FontStyle.normal : FontStyle.italic,

4. fontFamily

    fontFamily 为文字的字体,使用其他字体时需要倒入字体包资源文件并在 pubspec.yaml 中进行资源文件注册声明;可以从 Google Fonts 字体库中选择适当的字体类型;

fontFamily: 'DancingScript',
// pubspec.yaml
flutter:
  fonts:
    - family: DancingScript
      fonts:
        - asset: images/DancingScript-Regular.ttf

    小菜在添加字体时,遇到 A dependency specification must be a string or a mapping. 问题,其原因是字体资源的注册需要在 flutter: 中添加,而不是在 dependencies: 依赖中添加,dependencies: 都是添加的依赖键值对;

5. maxLines & ellipsis

    maxLines 为段落最长绘制行数,一般与 ellipsis 通过使用,ellipsis 为最后绘制不完时展示的文本内容;

maxLines: 4,
ellipsis: '...',

6. textDirection & textAlign

    textDirection & textAlign 的使用是小菜觉得应当注意的地方;textDirection 为文字绘制方向,ltrleft-to-right 从左至右;rtlright-to-left 从右至左,类似于 'ar/fa/he/ps/ur' 阿拉伯语和希伯来语等;textAlign 为文本的对齐方式;

    使用 rtl 方式时,标点均会展示在左侧,符合从右向左的绘制顺序;TextAlign 对齐方式注意区分 left / startright / end 的不同;

  • TextAlign.center 文本内容居中
  • TextAlign.justifyTextDirection 设置为准,自动延展填充至容器宽度
  • TextAlign.left 均与容器左侧对齐
  • TextAlign.startTextDirection 设置为准,开始位置进行对齐
  • TextAlign.right 均与容器右侧对齐
  • TextAlign.endTextDirection 设置为准,结束位置进行对齐
textAlign: _paragraphTextAlign(i),
textDirection: (i % 2 == 0) ? TextDirection.ltr : TextDirection.rtl,

// TextAlign & TextDirection
enum TextAlign { left, right, center, justify, start, end, }
enum TextDirection { ltr, rtl }

7. height

    height 简单理解为行高,但并非完全与 fontSize 倍数一致;

height: 2,

8. strutStyle

    strutStyle 小菜理解为段落高度属性,通过设置一系列垂直方向的维度定义更高级的行高属性;其中 StrutStyle 设置的 fontSize / fontFamily 等都是以此为基准线,借此改变的是段落行高,而不会改变段落文本属性(字号/字体等);

ParagraphBuilder _pb = ParagraphBuilder(ParagraphStyle(
  height: 2, fontSize: 17,
  strutStyle: ui.StrutStyle(fontFamily: 'DancingScript', fontSize: 20, height: 2),
))

ParagraphBuilder

1. pushStyle()

    pushStyle() 将给定的 TextStyle 样式添加到文本属性中,包括文字的颜色,背景等一系列样式;

    TextStyle 中涉及多种文本样式,对于与 ParagraphStyle 段落属性相同的 fontSize / fontFamily 等,以 TextStyle 为准;其中对于文本颜色,color 不能与 foreground 一同使用;wordSpacing 为单词间隔,letterSpacing 为文字字母之间间隔,两者要有区分;

var _gradient = ui.Gradient.linear(
    Offset(0.0, 0.0),
    Offset(0.0, size.height),
    [Colors.orange, Colors.deepOrange, Colors.green],
    [0 / 3, 1 / 3, 2 / 3]);
var _bgGradient = ui.Gradient.linear(
    Offset(0.0, 0.0),
    Offset(0.0, size.height),
    [Colors.blueGrey, Colors.white, Colors.grey],
    [0 / 3, 1 / 3, 2 / 3]);
var _shadow = [
  Shadow(offset: Offset(2.0, 2.0), blurRadius: 4.0, color: Colors.grey)
];
ParagraphBuilder _pb = ParagraphBuilder(ParagraphStyle(fontSize: 17))
  ..pushStyle(ui.TextStyle(
      // color: Colors.green,
      foreground: Paint()..shader = _gradient,
      // background: Paint()..shader = _bgGradient,
      fontSize: 20,
      fontWeight: FontWeight.w700,
      wordSpacing: 4,
      letterSpacing: 2,
      shadows: _shadow))
  ..addText(str);
ParagraphConstraints pc = ParagraphConstraints(width: size.width - 100);
Paragraph paragraph = _pb.build()..layout(pc);
canvas.drawParagraph(paragraph, Offset(50.0, 50 + _spaceHeight));

2. addText()

    addText() 将给定的文本添加到段落中,并以设置好的段落样式进行绘制;

3. addPlaceholder()

    addPlaceholder() 为文字绘制中设置占位区域;若在 addText() 之前设置优先展示占位区域在进行文本绘制,若在之后设置则是文本绘制结束后添加占位;且有多种垂直占位对齐方式;

for (int i = 0; i < 3; i++) {
  ParagraphBuilder _pb = ParagraphBuilder(ParagraphStyle(fontSize: 18))
    ..pushStyle(ui.TextStyle(
        foreground: Paint()..shader = _gradient,
        fontWeight: FontWeight.w700, wordSpacing: 4));
  if (i == 0) {
    _pb = _pb..addPlaceholder(60, 60, i <= 1 ? PlaceholderAlignment.bottom : PlaceholderAlignment.middle);
    _pb = _pb..addText(str);
  } else {
    _pb = _pb..addText(str);
    _pb = _pb..addPlaceholder(60, 60, i <= 1 ? PlaceholderAlignment.bottom : PlaceholderAlignment.middle);
  }
  ParagraphConstraints pc = ParagraphConstraints(width: size.width - 100);
  Paragraph paragraph = _pb.build()..layout(pc);
  canvas.drawParagraph(paragraph, Offset(50.0, 50 + _spaceHeight));
  canvas.drawRect(
      Rect.fromPoints(Offset(49.0, 50.0 + _spaceHeight),
          Offset(size.width - 49, 50.0 + paragraph.height + _spaceHeight)),
      _paint..shader = _gradient);
  _spaceHeight += paragraph.height;
}

    小菜对于 Canvas.drawParagraph 的尝试暂时到目前为止,还有很多特有属性会在实际过程中进行研究尝试;如有错误,请多多指导!


    Canvas.drawParagraph 案例源码


来源: 阿策小和尚
目录
相关文章
|
4天前
|
前端开发 搜索推荐 开发者
【Flutter前端技术开发专栏】Flutter中的自定义主题与暗黑模式
【4月更文挑战第30天】本文介绍了如何在Flutter中自定义主题和实现暗黑模式。通过`ThemeData`类定义应用的外观,包括颜色、字体和样式。示例展示了如何设置主色、强调色及文本、按钮主题。暗黑模式可通过`darkTheme`属性启用,结合`ThemeData.dark()`方法定制。利用`MediaQuery`监听系统亮度变化,动态调整暗黑模式状态。Flutter的这些特性有助于开发者创建独特且用户友好的界面。
【Flutter前端技术开发专栏】Flutter中的自定义主题与暗黑模式
|
4天前
|
缓存 前端开发 搜索推荐
【Flutter前端技术开发专栏】Flutter中的自定义绘制与Canvas API
【4月更文挑战第30天】Flutter允许开发者通过`CustomPaint`和`CustomPainter`进行自定义绘制,以实现丰富视觉效果。`CustomPaint` widget将`CustomPainter`应用到画布,而`CustomPainter`需实现`paint`和`shouldRepaint`方法。`paint`用于绘制图形,如示例中创建的`MyCirclePainter`绘制蓝色圆圈。Canvas API提供绘制形状、路径、文本和图片等功能。注意性能优化,避免不必要的重绘和利用缓存提升效率。自定义绘制让Flutter UI更具灵活性和个性化,但也需要图形学知识和性能意识。
【Flutter前端技术开发专栏】Flutter中的自定义绘制与Canvas API
|
4天前
|
开发框架 前端开发 搜索推荐
【Flutter前端技术开发专栏】Flutter中的自定义Widget与渲染流程
【4月更文挑战第30天】探索Flutter的自定义Widget与渲染流程。自定义Widget是实现复杂UI设计的关键,优点在于个性化设计、功能扩展和代码复用,但也面临性能优化和复杂性管理的挑战。创建步骤包括设计结构、定义Widget类、实现构建逻辑和处理交互。Flutter渲染流程涉及渲染对象树、布局、绘制和合成阶段。实践案例展示如何创建带渐变背景和阴影的自定义按钮。了解这些知识能提升应用体验并应对开发挑战。查阅官方文档以深入学习。
【Flutter前端技术开发专栏】Flutter中的自定义Widget与渲染流程
|
4天前
|
前端开发 开发者 UED
Flutter的自定义Painter:深入探索自定义绘制Widget的技术实现
【4月更文挑战第26天】Flutter的自定义Painter允许开发者根据需求绘制独特UI,通过继承`CustomPaint`类和重写`paint`方法实现。在`paint`中使用`Canvas`绘制图形、路径等。创建自定义Painter类后,将其作为`CustomPaint` Widget的`painter`属性使用。此技术可实现自定义形状、渐变、动画等复杂效果,提升应用视觉体验。随着Flutter的进化,自定义Painter将提供更丰富的功能。
|
4天前
|
运维 监控 定位技术
应用研发平台EMAS常见问题之flutter插件不支持自定义图标如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
81 0
|
4天前
|
前端开发 开发者
Flutter Canvas 属性详解与实际运用
Flutter Canvas 属性详解与实际运用
31 1
|
4天前
|
Dart 前端开发
Flutter笔记:绘图示例 - 一个简单的(Canvas )时钟应用
Flutter笔记:绘图示例 - 一个简单的(Canvas )时钟应用
96 0
|
4天前
Flutter 自定义ICON库
Flutter 自定义ICON库 Flutter提供了一些内置的ICON库,但在实际开发中,可能需要一些自定义的ICON图标。Flutter允许我们使用自定义图标,本文将介绍如何创建和使用自定义ICON库。
|
移动开发 Dart 小程序
基于Flutter的Canvas探索与应用
目前在小程序互动场景下遇到的业务痛点,并且给出了基于Flutter引擎的解法。基于Flutter引擎,对外提供标准的Web Canvas API和并利用flutter渲染管线,让业务代码在小程序worker线程中直接渲染,缩短了渲染链路,提高了渲染性能。本次分享将由淘宝技术部无线开发专家万红波为大家分享目前在小程序互动场景下遇到的业务痛点,以及基于Flutter引擎的解法。
2266 0
基于Flutter的Canvas探索与应用
|
4天前
|
缓存 监控 前端开发
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
【4月更文挑战第30天】本文探讨了Flutter应用启动优化策略,包括理解启动过程、资源加载优化、减少初始化工作、界面布局简化、异步初始化、预加载关键数据、性能监控分析以及案例和未来优化方向。通过这些方法,可以缩短启动时间,提升用户体验。使用Flutter DevTools等工具可助于识别和解决性能瓶颈,实现持续优化。
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略