Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion lib/flutter_auto_size_text.dart
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
export 'src/auto_size_text.dart';
library;

import 'dart:async';
import 'dart:math';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

part 'src/auto_size_group.dart';

part 'src/auto_size_group_builder.dart';

part 'src/auto_size_text.dart';

part 'src/text_fitter.dart';

part 'src/auto_size_builder/auto_size.dart';

part 'src/auto_size_builder/auto_size_builder.dart';

part 'src/auto_size_builder/auto_size_element.dart';

part 'src/auto_size_builder/render_auto_size.dart';
14 changes: 11 additions & 3 deletions lib/src/auto_size_builder/auto_size.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
part of 'auto_size_builder.dart';
part of '../../flutter_auto_size_text.dart';

class _AutoSize extends RenderObjectWidget {
_AutoSize({
Expand All @@ -17,13 +17,15 @@ class _AutoSize extends RenderObjectWidget {
required this.textScaleFactor,
required this.minFontSize,
required this.maxFontSize,
this.groupMaxFontSize,
required this.stepGranularity,
required this.presetFontSizes,
this.onMaxPossibleFontSizeChanged,
}) {
_validateProperties();
}

final AutoSizeTextBuilder builder;
final _AutoSizeTextBuilder builder;
final Widget? overflowReplacement;

final TextSpan text;
Expand All @@ -41,6 +43,8 @@ class _AutoSize extends RenderObjectWidget {
final double maxFontSize;
final double stepGranularity;
final List<double>? presetFontSizes;
final double? groupMaxFontSize;
final void Function(double)? onMaxPossibleFontSizeChanged;

TextFitter _buildFitter() {
return TextFitter(
Expand All @@ -64,13 +68,17 @@ class _AutoSize extends RenderObjectWidget {

@override
_RenderAutoSize createRenderObject(BuildContext context) {
return _RenderAutoSize(fitter: _buildFitter());
return _RenderAutoSize(
fitter: _buildFitter(),
onMaxPossibleFontSizeChanged: onMaxPossibleFontSizeChanged,
groupMaxFontSize: groupMaxFontSize);
}

@override
void updateRenderObject(
BuildContext context, covariant _RenderAutoSize renderObject) {
renderObject.updateTextFitter(_buildFitter());
renderObject.updateGroupMaxFontSize(groupMaxFontSize);
}

@override
Expand Down
57 changes: 43 additions & 14 deletions lib/src/auto_size_builder/auto_size_builder.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_auto_size_text/src/text_fitter.dart';
part of '../../flutter_auto_size_text.dart';

part 'auto_size.dart';
part 'auto_size_element.dart';
part 'render_auto_size.dart';
typedef _AutoSizeTextBuilder = Widget Function(BuildContext context,
double textScaleFactor, double? groupMaxFontSize, bool overflow);

typedef AutoSizeTextBuilder = Widget Function(
BuildContext context, double textScaleFactor, bool overflow);

class AutoSizeBuilder extends StatefulWidget {
const AutoSizeBuilder({
class _AutoSizeBuilder extends StatefulWidget {
const _AutoSizeBuilder({
super.key,
required this.builder,
this.overflowReplacement,
Expand All @@ -30,9 +24,10 @@ class AutoSizeBuilder extends StatefulWidget {
this.maxFontSize,
this.stepGranularity,
this.presetFontSizes,
this.group,
});

final AutoSizeTextBuilder builder;
final _AutoSizeTextBuilder builder;

/// {@macro auto_size_text.overflowReplacement}
final Widget? overflowReplacement;
Expand Down Expand Up @@ -83,11 +78,29 @@ class AutoSizeBuilder extends StatefulWidget {
/// {@macro auto_size_text.presetFontSizes}
final List<double>? presetFontSizes;

/// {@macro auto_size_text.group}
final AutoSizeGroup? group;

@override
State<AutoSizeBuilder> createState() => _AutoSizeBuilderState();
State<_AutoSizeBuilder> createState() => _AutoSizeBuilderState();
}

class _AutoSizeBuilderState extends State<AutoSizeBuilder> {
class _AutoSizeBuilderState extends State<_AutoSizeBuilder> {
@override
void initState() {
super.initState();
widget.group?._register(this);
}

@override
void didUpdateWidget(covariant _AutoSizeBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.group != widget.group) {
oldWidget.group?._remove(this);
widget.group?._register(this);
}
}

@override
Widget build(BuildContext context) {
final defaultTextStyle = DefaultTextStyle.of(context);
Expand Down Expand Up @@ -127,8 +140,24 @@ class _AutoSizeBuilderState extends State<AutoSizeBuilder> {
textScaleFactor: widget.textScaleFactor ?? 1,
minFontSize: widget.minFontSize ?? 12.0,
maxFontSize: widget.maxFontSize ?? double.infinity,
groupMaxFontSize: widget.group?._effectiveMaxPossibleFontSize,
stepGranularity: widget.stepGranularity ?? 1.0,
presetFontSizes: widget.presetFontSizes,
onMaxPossibleFontSizeChanged: widget.group != null
? (maxPossibleFontSize) {
widget.group?._updateFontSize(this, maxPossibleFontSize);
}
: null,
);
}

void _notifySync() {
setState(() {});
}

@override
void dispose() {
widget.group?._remove(this);
super.dispose();
}
}
6 changes: 3 additions & 3 deletions lib/src/auto_size_builder/auto_size_element.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
part of 'auto_size_builder.dart';
part of '../../flutter_auto_size_text.dart';

class _AutoSizeElement extends RenderObjectElement {
_AutoSizeElement(_AutoSize super.widget);
Expand Down Expand Up @@ -40,12 +40,12 @@ class _AutoSizeElement extends RenderObjectElement {
super.unmount();
}

void _updateText(double textScaleFactor, bool overflow) {
void _updateText(double textScaleFactor, double? groupMaxFontSize, bool overflow) {
owner!.buildScope(this, () {
_overflow = overflow;
Widget built;
try {
built = widget.builder(this, textScaleFactor, overflow);
built = widget.builder(this, textScaleFactor, groupMaxFontSize, overflow);
debugWidgetBuilderValue(widget, built);
} catch (e) {
built = ErrorWidget(e);
Expand Down
29 changes: 23 additions & 6 deletions lib/src/auto_size_builder/render_auto_size.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
part of 'auto_size_builder.dart';
part of '../../flutter_auto_size_text.dart';

class _AutoSizeParentData extends ParentData
with ContainerParentDataMixin<RenderBox> {}
Expand All @@ -7,23 +7,31 @@ class _RenderAutoSize extends RenderBox
with
ContainerRenderObjectMixin<RenderBox,
ContainerParentDataMixin<RenderBox>> {
_RenderAutoSize({required TextFitter fitter}) : _fitter = fitter;
_RenderAutoSize(
{required TextFitter fitter,
this.onMaxPossibleFontSizeChanged,
required this.groupMaxFontSize})
: _fitter = fitter;

var _overflow = false;
var _needsBuild = true;
double? _previousTextScaleFactor;
bool? _previousOverflow;
double? _longestWordWidth;

Function(double, bool)? _buildCallback;
void updateBuildCallback(Function(double, bool)? buildCallback) {
Function(double, double?, bool)? _buildCallback;
double? groupMaxFontSize;
final void Function(double)? onMaxPossibleFontSizeChanged;

void updateBuildCallback(Function(double, double?, bool)? buildCallback) {
if (_buildCallback == buildCallback) return;
_previousTextScaleFactor = null;
_buildCallback = buildCallback;
markNeedsLayout();
}

TextFitter _fitter;

void updateTextFitter(TextFitter fitter) {
if (_fitter == fitter) return;
if (_fitter.text != fitter.text) {
Expand All @@ -34,6 +42,12 @@ class _RenderAutoSize extends RenderBox
markNeedsLayout();
}

void updateGroupMaxFontSize(double? newGroupMaxFontSize) {
if (groupMaxFontSize == newGroupMaxFontSize) return;
groupMaxFontSize = newGroupMaxFontSize;
markNeedsLayout();
}

RenderBox get child => _overflow ? lastChild! : firstChild!;

bool get hasReplacement => !identical(firstChild, lastChild);
Expand Down Expand Up @@ -115,8 +129,11 @@ class _RenderAutoSize extends RenderBox
_previousTextScaleFactor = result.scale;
_previousOverflow = result.overflow;
_needsBuild = false;
invokeLayoutCallback(
(_) => _buildCallback!(result.scale, result.overflow));
final fontSize = _fitter.text.style?.fontSize ?? _kDefaultFontSize;
final maxPossibleFontSize = fontSize * result.scale;
onMaxPossibleFontSizeChanged?.call(maxPossibleFontSize);
invokeLayoutCallback((_) =>
_buildCallback!(result.scale, groupMaxFontSize, result.overflow));
}

_overflow = result.overflow;
Expand Down
49 changes: 49 additions & 0 deletions lib/src/auto_size_group.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
part of '../flutter_auto_size_text.dart';

/// Controller to synchronize the fontSize of multiple AutoSizeTexts.
class AutoSizeGroup {
final _listeners = <_AutoSizeBuilderState, double>{};
var _widgetsNotified = false;

void _register(_AutoSizeBuilderState text) {
_listeners[text] = double.infinity;
}

double get _effectiveMaxPossibleFontSize {
final minMaxPossibleFontSize = _listeners.values.fold<double>(
double.infinity,
(previousValue, element) =>
element < previousValue ? element : previousValue);
return minMaxPossibleFontSize;
}

void _updateFontSize(_AutoSizeBuilderState text, double maxPossibleFontSize) {
final oldEffectiveMaxPossibleFontSize = _effectiveMaxPossibleFontSize;
_listeners[text] = maxPossibleFontSize;
final newEffectiveMaxPossibleFontSize = _effectiveMaxPossibleFontSize;

if (oldEffectiveMaxPossibleFontSize != newEffectiveMaxPossibleFontSize) {
_widgetsNotified = false;
scheduleMicrotask(_notifyListeners);
}
}

void _notifyListeners() {
if (_widgetsNotified) {
return;
} else {
_widgetsNotified = true;
}

for (final textState in _listeners.keys) {
if (textState.mounted) {
textState._notifySync();
}
}
}

void _remove(_AutoSizeBuilderState text) {
_updateFontSize(text, double.infinity);
_listeners.remove(text);
}
}
22 changes: 22 additions & 0 deletions lib/src/auto_size_group_builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
part of '../flutter_auto_size_text.dart';

/// A Flutter widget that provides an [AutoSizeGroup] to its builder function.
class AutoSizeGroupBuilder extends StatefulWidget {
final Widget Function(BuildContext context, AutoSizeGroup autoSizeGroup)
builder;

/// Creates an [AutoSizeGroupBuilder] widget.
const AutoSizeGroupBuilder({super.key, required this.builder});

@override
_AutoSizeGroupBuilderState createState() => _AutoSizeGroupBuilderState();
}

class _AutoSizeGroupBuilderState extends State<AutoSizeGroupBuilder> {
final _group = AutoSizeGroup();

@override
Widget build(BuildContext context) {
return widget.builder(context, _group);
}
}
Loading