搜索插件、代码仓与 APP 分类

optimal_wrap_text 封面
插件详情v1.5.0

optimal_wrap_text

一个 Flutter Text 的替代品,可将短的多行文本包裹在视觉上大小相似的行中,以获得更好的视觉平衡。

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
825
喜欢数
25
Pub 分数
160

安装插件

flutter pub add optimal_wrap_text

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

OptimalWrapText 是一个 Flutter 小部件,通过智能地将多行文本换行,以创建长度相似的视觉平衡行来增强文本布局。与标准 Text 小部件不同,它能最大限度地减少不均匀的换行,从而在短段落或标签的 UI 中提高可读性和美观性。它非常适合对排版和谐性有要求的界面,例如仪表板、卡片或表单。该包支持所有主要平台,并可无缝集成到现有的 Flutter 项目中。

适合场景

  • 改善文字密集型用户界面的视觉平衡
  • 在紧凑布局中提高可读性
  • 在标签和卡片中创建一致的行长度
  • 优化响应式设计中的文本显示
  • 在仪表板和数据摘要中使用

主要特点

  • 智能平衡行长度
  • 减少不自然的换行
  • 支持所有 Flutter 平台
  • 与现有 Text 小部件的简单集成
  • 保留原始文本内容和样式

适合对象

  • 注重排版和谐的设计人员
  • 开发响应式 UI 的开发者
  • 包含密集文本内容的应用程序
  • 需要精美文本展示的项目
  • 专注于用户体验的团队细节

使用建议

  • 可能会略微增加渲染复杂性
  • 由于性能原因,不适合非常长的文本
  • 超出平衡线以外的定制化有限
  • 需要在不同屏幕尺寸上进行仔细测试
  • 最适合与短至中等长度的文本块一起使用

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

Optimal Wrap Text

A Flutter Text replacement that wraps short multi-line text over similarly sized lines for better visual balance.

Instead of awkward standard line breaks like these:

My slightly longer text that will span 2 or
3 lines

My slightly longer text that will span 2 or
                  3 lines

You get cleaner, balanced output like these:

My slightly longer text that 
will span 2 or 3 lines

        My slightly longer text that       
           will span 2 or 3 lines

Perfect for small, informative footnotes or short multi-line messages that deserve to look good.

Before and After Comparison

✨ Features

  • Drop-in replacement for the Text widget
  • Supports all Text attributes, including style, textDirection (RTL), textHeightBehavior…
  • Rich text via OptimalWrapRichText, including WidgetSpan (icons and other inline widgets)
  • Automatically finds optimal line breaks — no more manual \n
  • Optional minLines to wrap onto at least that many lines when there are enough words
  • Adjusts to different screen sizes and text scaling

🚀 Getting started

Add optimal_wrap_text to your pubspec.yaml:

dependencies:
  ...
  optimal_wrap_text: 1.5.0
  ...

Then import it:

import 'package:optimal_wrap_text/optimal_wrap_text.dart';

Use it just like the Text widget:

OptimalWrapText(
  'My slightly longer text that will span 2 or 3 lines',
)

For rich text, use OptimalWrapRichText the same way you would use Text.rich:

OptimalWrapRichText(
  TextSpan(
    children: [
      TextSpan(text: 'My slightly '),
      TextSpan(
        text: 'longer',
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
      TextSpan(text: ' rich text that will span 2 or 3 lines'),
    ],
  ),
)

WidgetSpans (for example icons) are supported too:

OptimalWrapRichText(
  TextSpan(
    children: [
      WidgetSpan(
        alignment: PlaceholderAlignment.middle,
        child: Icon(Icons.info_outline, size: 16),
      ),
      TextSpan(text: ' My slightly longer text that will span 2 or 3 lines'),
    ],
  ),
)

With all supported properties:

OptimalWrapText(
  'My slightly longer text that will span 2 or 3 lines',
  key: ...
  style: Theme.of(context).textTheme.bodyLarge,
  textAlign: TextAlign.center,
  strutStyle: ...,
  textDirection: ...,
  locale: ...,
  softWrap: ...,
  overflow: ...,
  textScaler: ...,
  minLines: ...,
  maxLines: ...,
  semanticsLabel: ...,
  textWidthBasis: ...,
  textHeightBehavior: ...,
  selectionColor: ...,
)

📌 For centered or right-aligned text, you may still want to wrap it in a Center, Align, or Row, just like with a regular Text widget.

Use minLines to wrap onto at least that many lines when the text has enough words. A single unbreakable word is never forced to break.

OptimalWrapText(
  'Hello there friend',
  minLines: 2,
  textAlign: TextAlign.center,
)

Use shrinkWrap: true when the parent should hug the optimally wrapped width (for example a chip or speech bubble). By default the widgets expand to the available width via Align, matching typical full-width text layout.

OptimalWrapRichText(
  textSpan,
  shrinkWrap: true,
  textAlign: TextAlign.center,
)

For custom rich-text children, wrap them with the exported OptimalWrapChild primitive instead.

🧠 How does it work?

  1. Optimal Wrap Text uses TextPainter to determine how many lines your text will take at full available width in the given widget tree.

  2. It runs a binary search to find the narrowest width that still fits in the same number of lines — ensuring optimal wrapping. With minLines, that target is raised so the text wraps onto at least that many lines when there are enough words.

    e.g.

    300px → 2 lines (width from the current BuildContext)
    150px → 4 lines ❌
    225px → 2 lines ✅
    188px → 3 lines ❌
    206px → 2 lines ✅
    ... and so on
    

    Worst-case scenario for mobile screen widths (e.g. iPhone) is about 9 iterations, but typical cases resolve in 6 attempts.

  3. It wraps the final Text in a SizedBox constrained to that optimal width.

⚠️ Known Limitations

It uses LayoutBuilder to get width in the given widget tree, which doesn’t work inside some slivers, such as SliverFillRemaining, which rely on intrinsic sizing.

For OptimalWrapRichText with WidgetSpans, prefer intrinsically sized inline children (icons, small badges, fixed-size boxes). Same as Flutter’s Text.rich, each inline widget is constrained by the paragraph’s max width — very wide or full-bleed children can prevent meaningful narrowing.

💡 You can work around this by passing a manual width:

CustomScrollView(
  slivers: [
    ...,
    SliverFillRemaining(
      child: Padding(
        padding: EdgeInsets.only(left: 15, right: 30),
        child: OptimalWrapText(
          'My slightly longer text that will span 2 or 3 lines',
          width: MediaQuery.sizeOf(context).width - 15 - 30
        ),
      )
    ),
  ]
)

📄 Copyright and License

Optimal Wrap Text is maintained by Chris Rutkowski as part of the Commingle app, and open-sourced under the MIT License.

所属分类

源码仓库

使用此插件的项目

暂无相关数据。