fit_text 0.1.1 copy "fit_text: ^0.1.1" to clipboard
fit_text: ^0.1.1 copied to clipboard

Text that shrinks to fit its box, correctly. Works inside Expanded, Row, IntrinsicHeight and unbounded constraints, where LayoutBuilder-based auto-sizing gives up.

fit_text #

Text that shrinks to fit its box — including in the places auto-sizing usually breaks.

FitText('A headline that must never wrap', maxLines: 1, minFontSize: 12)

The problem this fixes #

Flutter has no built-in way to make text fit: Text overflows or clips. The established workaround measures inside a LayoutBuilder, and that works right up until the widget lands somewhere Flutter needs an intrinsic size first:

LayoutBuilder does not support returning intrinsic dimensions.
  at _RenderLayoutBuilder.computeMaxIntrinsicHeight

That is a hard framework limitation, not a bug someone forgot to fix. It rules LayoutBuilder-based auto-sizing out of:

  • IntrinsicHeight and IntrinsicWidth
  • Table cells — columns size with intrinsics by default
  • Baseline-aligned rows

FitText does the fitting inside its own RenderBox, during layout. Intrinsics are answered honestly, so it works in all of those. There is a test in the suite that pins the LayoutBuilder failure alongside FitText succeeding in the same tree, so the difference is verified rather than asserted.

Install #

dependencies:
  fit_text: ^0.1.0

Usage #

// Shrink to fit one line, never below 12.
FitText('Long product name', maxLines: 1, minFontSize: 12)

// Grow to fill, but stay on your type scale.
FitText('42', presetFontSizes: [16, 24, 32, 48, 64])

// Rich text — nested sizes scale proportionally.
FitText.rich(
  TextSpan(text: 'Total ', children: [
    TextSpan(text: '£42', style: TextStyle(fontWeight: FontWeight.bold)),
  ]),
  maxLines: 1,
)

Both constructors are const, like Text.

Matching sizes across widgets #

Independently fitted labels land on different sizes, which looks wrong across a row of buttons. A group makes them agree on the smallest size any member needed, so they match and all of them still fit.

final labels = FitTextGroup();   // hold this in state

Row(children: [
  Expanded(child: FitText('Save', group: labels, maxLines: 1)),
  Expanded(child: FitText('Discard changes', group: labels, maxLines: 1)),
]);

Members find their own size first and agree on the next frame, so a group settles one frame after its contents change.

Options #

minFontSize Floor. Below this the text overflows instead of shrinking further.
maxFontSize Ceiling. Defaults to the inherited style's size, so text shrinks but never grows unless you ask.
stepGranularity Increment between candidate sizes.
presetFontSizes An explicit scale, instead of a stepped range.
group Share a size with other members.

Everything Text takes — textAlign, maxLines, softWrap, overflow, strutStyle, textScaler, locale, textWidthBasis — behaves the same way.

Cost #

Finding the size is a bisection, not a scan: about log2((max - min) / step) text layouts, so six or so for the defaults. It re-runs only when the text, style, or constraints change, and RenderFitText.fittedFontSize exposes what it chose if you need to react to it.

Coming from auto_size_text #

The API is deliberately close, so most call sites change only the widget name.

auto_size_text fit_text
AutoSizeText(...) FitText(...)
AutoSizeText.rich(...) FitText.rich(...)
AutoSizeGroup() FitTextGroup()
group: myGroup group: myGroup

| overflowReplacement: | overflowReplacement: | | wrapWords: false | wrapWords: false |

Neither package supports text selection.

One difference worth knowing: overflowReplacement stays mounted whether or not it is used, collapsed to zero size — the same trade IndexedStack makes. That is what lets the swap happen inside a single layout pass with no frame of overflowing text, but it means an expensive replacement widget is built even when it never shows. Keep it cheap.

License #

MIT © K M Shahriar Hossain

1
likes
160
points
37
downloads

Documentation

Documentation
API reference

Publisher

verified publisherjumyn.com

Weekly Downloads

Text that shrinks to fit its box, correctly. Works inside Expanded, Row, IntrinsicHeight and unbounded constraints, where LayoutBuilder-based auto-sizing gives up.

Repository (GitHub)
View/report issues

Topics

#text #layout #typography #responsive #ui

License

MIT (license)

Dependencies

flutter

More

Packages that depend on fit_text