Flutter中如何计算一个Container可以完美填充多少文字

要想知道一个 Container 可以填满多少个文字,我们只需算出一行可以填充的文字数量,再算出可以填充的最大行数,将两者相乘就行。

遇到问题先干嘛?当然是用搜索引擎先检索一下答案。我检索到了一篇标题为《Flutter-如何计算文字宽高》的文章(因为我在站内没有搜到这篇文章,所有有兴趣的可以自己用搜索引擎检索查看),这篇文章使用了 TextPainter 来计算出文字的宽高。这里我就用 ParagraphBuilder 来完成计算。这可能并不是最好的,请根据需求酌情参考。

我们有如下一个示例:

显然,如果直接使用 Text 我们什么也做不了,所以我们得使用 CustomPaint 来显示绘制的文字。

dart 复制代码
class HomeView extends StatelessWidget {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          clipBehavior: Clip.hardEdge,
          decoration: const BoxDecoration(color: Colors.green),
          child: CustomPaint(
            painter: CustomTextPainter(),
          ),
        ),
      ),
    );
  }
}

class CustomTextPainter extends CustomPainter {

  @override
  void paint(Canvas canvas, Size size) {
    // ...
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => this != oldDelegate;
}

因为不是每次传入的文字大小都是一样的,所以我们需要在外部传入该值。

dart 复制代码
class HomeView extends StatelessWidget {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          clipBehavior: Clip.hardEdge,
          decoration: const BoxDecoration(color: Colors.green),
          child: CustomPaint(
            painter: CustomTextPainter(
              fontSize: 16,
              lineHeight: 1,
            ),
          ),
        ),
      ),
    );
  }
}

class CustomTextPainter extends CustomPainter {

  final double fontSize;
  final double lineHeight;

  CustomTextPainter({
    super.repaint,
    required this.fontSize,
    required this.lineHeight,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // ...
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => this != oldDelegate;
}

这里我们指定需要传入两个参数:文字大小和行高,知道这两个参数我们就很容易通过 文字大小 * 文字行高 来计算出文字所占的高度。

计算出了文字所占的高度,就能计算出可以完美显示所有文字的行数。

代码如下:

dart 复制代码
@override
void paint(Canvas canvas, Size size) {
  ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(ui.ParagraphStyle());
  paragraphBuilder.pushStyle(
    ui.TextStyle(
      color: Colors.white,
      fontSize: fontSize,
      height: lineHeight,
    ),
  );
  
  double fontHeight = fontSize * lineHeight;
  int fontLine = size.height ~/ fontHeight;
  print('每个文字的高度是:$fontHeight');  // 16
  print('完美呈现的文字行数是:$fontLine');  // 12
}

我们可以显示一段文字来验证下:

dart 复制代码
@override
void paint(Canvas canvas, Size size) {
  ...
    
  paragraphBuilder.addText('海水梦悠悠' * 100);
  ui.ParagraphConstraints paragraphConstraints = ui.ParagraphConstraints(width: size.width);
  ui.Paragraph paragraph = paragraphBuilder.build();
  paragraph.layout(paragraphConstraints);
  canvas.drawParagraph(paragraph, Offset.zero);
}

一共刚好 12 行。

现在知道了行数,接下来就只要算出一行可以填充几个文字就行。

想要知道一行可以填充几个文字,我们可以先算出一个字所占的宽度。我们先让界面只显示一个字:

dart 复制代码
@override
void paint(Canvas canvas, Size size) {
  ...
    
  paragraphBuilder.addText('海');
  ui.ParagraphConstraints paragraphConstraints = ui.ParagraphConstraints(width: size.width);
  ui.Paragraph paragraph = paragraphBuilder.build();
  paragraph.layout(paragraphConstraints);
  canvas.drawParagraph(paragraph, Offset.zero);
}

为什么要改成显示一个字?我们虽然无法计算出一个字的宽度,但是可以用 ParagraphcomputeLineMetrics 方法算出每一行文字所占的宽度。

dart 复制代码
@override
void paint(Canvas canvas, Size size) {
  ...
    
  paragraphBuilder.addText('海');
  ui.ParagraphConstraints paragraphConstraints = ui.ParagraphConstraints(width: size.width);
  ui.Paragraph paragraph = paragraphBuilder.build();
  paragraph.layout(paragraphConstraints);
  List<ui.LineMetrics> lines = paragraph.computeLineMetrics();
  double fontWidth = lines.first.width;
  print("第一行文字所占的宽度:$fontWidth");  // 16.000030517578125
  print("一行可以显示的文字个数:${size.width ~/ fontWidth}");  // 12
  canvas.drawParagraph(paragraph, Offset.zero);
}

为了验证一下是否准确,可以数一下下图填满时的个数:

通过以上的内容我们可以计算出,在一个 200*200 的 Container 中,可以完整显示文字大小为 16,行高为 1 的文字共 144 个。

以下是完整代码:

dart 复制代码
import 'dart:ui' as ui;

import 'package:flutter/material.dart';

class HomeView extends StatelessWidget {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          clipBehavior: Clip.hardEdge,
          decoration: const BoxDecoration(color: Colors.green),
          child: CustomPaint(
            painter: CustomTextPainter(
              fontSize: 16,
              lineHeight: 1,
            ),
          ),
        ),
      ),
    );
  }
}

class CustomTextPainter extends CustomPainter {
  final double fontSize;
  final double lineHeight;

  CustomTextPainter({
    super.repaint,
    required this.fontSize,
    required this.lineHeight,
  });

  @override
  void paint(Canvas canvas, Size size) {
    ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(ui.ParagraphStyle());
    paragraphBuilder.pushStyle(
      ui.TextStyle(
        color: Colors.white,
        fontSize: fontSize,
        height: lineHeight,
      ),
    );
    double fontHeight = fontSize * lineHeight;
    int fontLine = size.height ~/ fontHeight;
    print('每个文字的高度是 $fontHeight');
    print('完美呈现的文字行数是 $fontLine');

    paragraphBuilder.addText('海');
    ui.ParagraphConstraints paragraphConstraints = ui.ParagraphConstraints(width: size.width);
    ui.Paragraph paragraph = paragraphBuilder.build();
    paragraph.layout(paragraphConstraints);

    List<ui.LineMetrics> lines = paragraph.computeLineMetrics();
    double fontWidth = lines.first.width;
    print("第一行文字所占的宽度:$fontWidth");
    print("一行可以显示的文字个数:${size.width ~/ fontWidth}");

    canvas.drawParagraph(paragraph, Offset.zero);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => this != oldDelegate;
}

当然,在实际应用中,我们不可能让"海"字显示出来,并且只能应用于中文日文之类的文字,如果插入了英文字母数字之类的可能就不准确了。

相关推荐
小蜜蜂嗡嗡10 小时前
flutter封装vlcplayer的控制器
前端·javascript·flutter
你听得到1120 小时前
从需求到封装:手把手带你打造一个高复用、可定制的Flutter日期选择器
前端·flutter
哲科软件1 天前
跨平台开发的抉择:Flutter vs 原生安卓(Kotlin)的优劣对比与选型建议
android·flutter·kotlin
天涯海风1 天前
Kuikly 与 Flutter 的全面对比分析,结合技术架构、性能、开发体验等核心维度
flutter·kuikly
aiprtem1 天前
基于Flutter的web登录设计
前端·flutter
coder_pig1 天前
跟🤡杰哥一起学Flutter (三十四、玩转Flutter手势✋)
前端·flutter·harmonyos
程序员老刘1 天前
Android 16开发者全解读
android·flutter·客户端
Jalor1 天前
Flutter + 鸿蒙 | Flutter 跳转鸿蒙原生界面
flutter·harmonyos
吴Wu涛涛涛涛涛Tao2 天前
一步到位:用 Very Good CLI × Bloc × go_router 打好 Flutter 工程地基
flutter·ios
九丝城主2 天前
2025使用VM虚拟机安装配置Macos苹果系统下Flutter开发环境保姆级教程--中篇
服务器·flutter·macos·vmware