diff --git a/.gitignore b/.gitignore
index b18ee3e..8ade072 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,9 +7,10 @@
.packages
.pub/
-build/
-ios/
-android/
+**/build/
+**/ios/
+**/android/
+**/web
pubspec.lock
doc/api/
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e81e2b..bea079c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 4.0.0
+- Added `AutoSizeBuilder`, `SelectableAutoSize`, `AutoSizeTextField` and `AutoSizeGroupBuilder`
+- Added `textWidthBasis` and `textHeightBehavior`
+- Changed default `wordWrap` to `false`
+- Improved performance
+- Fixed intrinsics handling
+- Fixed `wordWrap` calculation for rich text
+
## 3.0.0
- Upgraded to null safety
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 7f38dd4..ea6e039 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,46 +1,8 @@
-include: package:pedantic/analysis_options.yaml
+include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
- "**/*.g.dart"
strong-mode:
implicit-casts: false
- implicit-dynamic: false
- errors:
- todo: error
- include_file_not_found: ignore
-linter:
- rules:
- - avoid_function_literals_in_foreach_calls
- - avoid_renaming_method_parameters
- - avoid_returning_null
- - avoid_unused_constructor_parameters
- - await_only_futures
- - camel_case_types
- - cancel_subscriptions
- - comment_references
- - constant_identifier_names
- - control_flow_in_finally
- - directives_ordering
- - empty_statements
- - implementation_imports
- - invariant_booleans
- - iterable_contains_unrelated_type
- - list_remove_unrelated_type
- - no_adjacent_strings_in_list
- - non_constant_identifier_names
- - only_throw_errors
- - overridden_fields
- - package_api_docs
- - package_names
- - package_prefixed_library_names
- - prefer_final_locals
- - prefer_initializing_formals
- - prefer_interpolation_to_compose_strings
- - prefer_typing_uninitialized_variables
- - test_types_in_equals
- - throw_in_finally
- - unnecessary_brace_in_string_interps
- - unnecessary_getters_setters
- - unnecessary_lambdas
- - unnecessary_statements
+ implicit-dynamic: false
\ No newline at end of file
diff --git a/demo/.gitignore b/demo/.gitignore
deleted file mode 100644
index 528f3e6..0000000
--- a/demo/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-!android/
diff --git a/demo/analysis_options.yaml b/demo/analysis_options.yaml
new file mode 100644
index 0000000..61b6c4d
--- /dev/null
+++ b/demo/analysis_options.yaml
@@ -0,0 +1,29 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at
+ # https://dart-lang.github.io/linter/lints/index.html.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/demo/android/.gitignore b/demo/android/.gitignore
deleted file mode 100644
index 65b7315..0000000
--- a/demo/android/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-*.iml
-*.class
-.gradle
-/local.properties
-/.idea/workspace.xml
-/.idea/libraries
-.DS_Store
-/build
-/captures
-GeneratedPluginRegistrant.java
diff --git a/demo/android/app/build.gradle b/demo/android/app/build.gradle
deleted file mode 100644
index 73116aa..0000000
--- a/demo/android/app/build.gradle
+++ /dev/null
@@ -1,38 +0,0 @@
-def localProperties = new Properties()
-def localPropertiesFile = rootProject.file('local.properties')
-if (localPropertiesFile.exists()) {
- localPropertiesFile.withReader('UTF-8') { reader ->
- localProperties.load(reader)
- }
-}
-
-def flutterRoot = localProperties.getProperty('flutter.sdk')
-
-apply plugin: 'com.android.application'
-apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
-
-android {
- compileSdkVersion 27
-
- lintOptions {
- disable 'InvalidPackage'
- }
-
- defaultConfig {
- applicationId "com.github.leisim.auto_size_text.demo"
- minSdkVersion 16
- targetSdkVersion 27
- versionCode 1
- versionName 'v1'
- }
-
- buildTypes {
- release {
- signingConfig signingConfigs.debug
- }
- }
-}
-
-flutter {
- source '../..'
-}
diff --git a/demo/android/app/src/main/AndroidManifest.xml b/demo/android/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 1c5a59b..0000000
--- a/demo/android/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/demo/android/app/src/main/java/com/github/leisim/auto_size_text/demo/MainActivity.java b/demo/android/app/src/main/java/com/github/leisim/auto_size_text/demo/MainActivity.java
deleted file mode 100644
index a73d4e3..0000000
--- a/demo/android/app/src/main/java/com/github/leisim/auto_size_text/demo/MainActivity.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.github.leisim.auto_size_text.demo;
-
-import android.os.Bundle;
-import io.flutter.app.FlutterActivity;
-import io.flutter.plugins.GeneratedPluginRegistrant;
-
-public class MainActivity extends FlutterActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- GeneratedPluginRegistrant.registerWith(this);
- }
-}
diff --git a/demo/android/app/src/main/res/drawable/ic_launcher.png b/demo/android/app/src/main/res/drawable/ic_launcher.png
deleted file mode 100644
index d5f1c8d..0000000
Binary files a/demo/android/app/src/main/res/drawable/ic_launcher.png and /dev/null differ
diff --git a/demo/android/app/src/main/res/drawable/launch_background.xml b/demo/android/app/src/main/res/drawable/launch_background.xml
deleted file mode 100644
index 304732f..0000000
--- a/demo/android/app/src/main/res/drawable/launch_background.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/demo/android/app/src/main/res/values/styles.xml b/demo/android/app/src/main/res/values/styles.xml
deleted file mode 100644
index 5691c75..0000000
--- a/demo/android/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
diff --git a/demo/android/build.gradle b/demo/android/build.gradle
deleted file mode 100644
index d4225c7..0000000
--- a/demo/android/build.gradle
+++ /dev/null
@@ -1,29 +0,0 @@
-buildscript {
- repositories {
- google()
- jcenter()
- }
-
- dependencies {
- classpath 'com.android.tools.build:gradle:3.1.2'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- }
-}
-
-rootProject.buildDir = '../build'
-subprojects {
- project.buildDir = "${rootProject.buildDir}/${project.name}"
-}
-subprojects {
- project.evaluationDependsOn(':app')
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/demo/android/gradle.properties b/demo/android/gradle.properties
deleted file mode 100644
index 8bd86f6..0000000
--- a/demo/android/gradle.properties
+++ /dev/null
@@ -1 +0,0 @@
-org.gradle.jvmargs=-Xmx1536M
diff --git a/demo/android/gradle/wrapper/gradle-wrapper.jar b/demo/android/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 13372ae..0000000
Binary files a/demo/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/demo/android/gradle/wrapper/gradle-wrapper.properties b/demo/android/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 9372d0f..0000000
--- a/demo/android/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Fri Jun 23 08:50:38 CEST 2017
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/demo/android/gradlew b/demo/android/gradlew
deleted file mode 100644
index 9d82f78..0000000
--- a/demo/android/gradlew
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env bash
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
- echo "$*"
-}
-
-die ( ) {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
-esac
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/demo/android/gradlew.bat b/demo/android/gradlew.bat
deleted file mode 100644
index 8a0b282..0000000
--- a/demo/android/gradlew.bat
+++ /dev/null
@@ -1,90 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/demo/android/settings.gradle b/demo/android/settings.gradle
deleted file mode 100644
index 5a2f14f..0000000
--- a/demo/android/settings.gradle
+++ /dev/null
@@ -1,15 +0,0 @@
-include ':app'
-
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
-
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
- pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
-
-plugins.each { name, path ->
- def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
- include ":$name"
- project(":$name").projectDir = pluginDirectory
-}
diff --git a/demo/lib/main.dart b/demo/lib/main.dart
index a6c2a18..15cc89b 100644
--- a/demo/lib/main.dart
+++ b/demo/lib/main.dart
@@ -22,7 +22,7 @@ class App extends StatelessWidget {
DeviceOrientation.landscapeRight,
]);
- SystemChrome.setEnabledSystemUIOverlays([]);
+ SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
return MaterialApp(
theme: ThemeData.light(),
diff --git a/demo/lib/sync_demo.dart b/demo/lib/sync_demo.dart
index ea677b4..eb0d75c 100644
--- a/demo/lib/sync_demo.dart
+++ b/demo/lib/sync_demo.dart
@@ -4,6 +4,17 @@ import 'package:flutter/material.dart';
import 'text_card.dart';
import 'utils.dart';
+class SyncDemo extends StatelessWidget {
+ final bool richText;
+
+ SyncDemo(this.richText);
+
+ @override
+ Widget build(BuildContext context) {
+ return Container();
+ }
+}
+/*
class SyncDemo extends StatefulWidget {
final bool richText;
@@ -122,3 +133,4 @@ class _SyncDemoState extends State
);
}
}
+*/
\ No newline at end of file
diff --git a/demo/pubspec.yaml b/demo/pubspec.yaml
index 9ad504a..3a9a329 100644
--- a/demo/pubspec.yaml
+++ b/demo/pubspec.yaml
@@ -13,8 +13,8 @@ dependencies:
auto_size_text:
path: ../
- bottom_navy_bar: ^4.2.0
- material_design_icons_flutter: ^4.0.5755
+ bottom_navy_bar: 6.0.0
+ material_design_icons_flutter: ^5.0.6295
dev_dependencies:
flutter_test:
diff --git a/example/main.dart b/example/main.dart
deleted file mode 100644
index 9f71115..0000000
--- a/example/main.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-import 'package:auto_size_text/auto_size_text.dart';
-import 'package:flutter/material.dart';
-
-void main() {
- runApp(App());
-}
-
-class App extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- home: Scaffold(
- body: Center(
- child: SizedBox(
- width: 200,
- height: 140,
- child: AutoSizeText(
- 'This string will be automatically resized to fit in two lines.',
- style: TextStyle(fontSize: 30),
- maxLines: 2,
- ),
- ),
- ),
- ),
- );
- }
-}
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
deleted file mode 100644
index 81c05fd..0000000
--- a/example/pubspec.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: example
-description: AutoSizeText example
-
-version: 1.0.0
-
-environment:
- sdk: '>=2.12.0-0 <3.0.0'
-
-dependencies:
- flutter:
- sdk: flutter
-
- auto_size_text:
- path: ../
-
-dev_dependencies:
- flutter_test:
- sdk: flutter
-
-flutter:
- uses-material-design: true
-
-publish_to: none
\ No newline at end of file
diff --git a/lib/auto_size_text.dart b/lib/auto_size_text.dart
index 0ff37b6..3bab0ba 100644
--- a/lib/auto_size_text.dart
+++ b/lib/auto_size_text.dart
@@ -2,10 +2,7 @@
/// bounds.
library auto_size_text;
-import 'dart:async';
-
-import 'package:flutter/widgets.dart';
-
-part 'src/auto_size_text.dart';
-part 'src/auto_size_group.dart';
-part 'src/auto_size_group_builder.dart';
+export 'src/auto_size_builder/auto_size_builder.dart';
+export 'src/auto_size_text_field.dart';
+export 'src/auto_size_text.dart';
+export 'src/selectable_auto_size_text.dart';
diff --git a/lib/src/auto_size_builder/auto_size.dart b/lib/src/auto_size_builder/auto_size.dart
new file mode 100644
index 0000000..2bae2ce
--- /dev/null
+++ b/lib/src/auto_size_builder/auto_size.dart
@@ -0,0 +1,106 @@
+part of 'auto_size_builder.dart';
+
+class _AutoSize extends RenderObjectWidget {
+ _AutoSize({
+ Key? key,
+ required this.builder,
+ this.overflowReplacement,
+ required this.text,
+ required this.textAlign,
+ required this.textDirection,
+ this.minLines,
+ this.maxLines,
+ this.locale,
+ this.strutStyle,
+ required this.textWidthBasis,
+ this.textHeightBehavior,
+ required this.wrapWords,
+ required this.textScaleFactor,
+ required this.minFontSize,
+ required this.maxFontSize,
+ required this.stepGranularity,
+ required this.presetFontSizes,
+ }) : super(key: key) {
+ _validateProperties();
+ }
+
+ final AutoSizeTextBuilder builder;
+ final Widget? overflowReplacement;
+
+ final TextSpan text;
+ final TextAlign textAlign;
+ final TextDirection textDirection;
+ final int? minLines;
+ final int? maxLines;
+ final Locale? locale;
+ final StrutStyle? strutStyle;
+ final TextWidthBasis textWidthBasis;
+ final TextHeightBehavior? textHeightBehavior;
+ final bool wrapWords;
+ final double textScaleFactor;
+ final double minFontSize;
+ final double maxFontSize;
+ final double stepGranularity;
+ final List? presetFontSizes;
+
+ TextFitter _buildFitter() {
+ return TextFitter(
+ text: text,
+ textAlign: textAlign,
+ textDirection: textDirection,
+ minLines: minLines,
+ maxLines: maxLines,
+ locale: locale,
+ strutStyle: strutStyle,
+ textWidthBasis: textWidthBasis,
+ textHeightBehavior: textHeightBehavior,
+ wrapWords: wrapWords,
+ textScaleFactor: textScaleFactor,
+ minFontSize: minFontSize,
+ maxFontSize: maxFontSize,
+ stepGranularity: stepGranularity,
+ presetFontSizes: presetFontSizes,
+ );
+ }
+
+ @override
+ _RenderAutoSize createRenderObject(BuildContext context) {
+ return _RenderAutoSize(fitter: _buildFitter());
+ }
+
+ @override
+ void updateRenderObject(
+ BuildContext context, covariant _RenderAutoSize renderObject) {
+ renderObject.textFitter = _buildFitter();
+ }
+
+ @override
+ RenderObjectElement createElement() {
+ return _AutoSizeElement(this);
+ }
+
+ void _validateProperties() {
+ assert(maxLines == null || maxLines! > 0,
+ 'MaxLines must be greater than or equal to 1.');
+
+ if (presetFontSizes == null) {
+ assert(
+ stepGranularity >= 0.1,
+ 'StepGranularity must be greater than or equal to 0.1. It is not a '
+ 'good idea to resize the font with a higher accuracy.');
+ assert(
+ minFontSize >= 0, 'MinFontSize must be greater than or equal to 0.');
+ assert(maxFontSize > 0, 'MaxFontSize has to be greater than 0.');
+ assert(minFontSize <= maxFontSize,
+ 'MinFontSize must be smaller or equal than maxFontSize.');
+ assert(minFontSize / stepGranularity % 1 == 0,
+ 'MinFontSize must be a multiple of stepGranularity.');
+ if (maxFontSize != double.infinity) {
+ assert(maxFontSize / stepGranularity % 1 == 0,
+ 'MaxFontSize must be a multiple of stepGranularity.');
+ }
+ } else {
+ assert(presetFontSizes!.isNotEmpty, 'PresetFontSizes must not be empty.');
+ }
+ }
+}
diff --git a/lib/src/auto_size_builder/auto_size_builder.dart b/lib/src/auto_size_builder/auto_size_builder.dart
new file mode 100644
index 0000000..8314a97
--- /dev/null
+++ b/lib/src/auto_size_builder/auto_size_builder.dart
@@ -0,0 +1,136 @@
+import 'package:auto_size_text/src/text_fitter.dart';
+import 'package:flutter/rendering.dart';
+import 'package:flutter/widgets.dart';
+
+part 'auto_size_element.dart';
+part 'auto_size.dart';
+part 'render_auto_size.dart';
+
+typedef AutoSizeTextBuilder = Widget Function(
+ BuildContext context, double textScaleFactor, bool overflow);
+
+class AutoSizeBuilder extends StatefulWidget {
+ const AutoSizeBuilder({
+ Key? key,
+ required this.builder,
+ this.overflowReplacement,
+ required this.text,
+ this.style,
+ this.textAlign,
+ this.textDirection,
+ this.minLines,
+ this.maxLines,
+ this.locale,
+ this.strutStyle,
+ this.textWidthBasis,
+ this.textHeightBehavior,
+ this.wrapWords,
+ this.textScaleFactor,
+ this.minFontSize,
+ this.maxFontSize,
+ this.stepGranularity,
+ this.presetFontSizes,
+ }) : super(key: key);
+
+ final AutoSizeTextBuilder builder;
+
+ /// {@macro auto_size_text.overflowReplacement}
+ final Widget? overflowReplacement;
+
+ final TextSpan text;
+
+ final TextStyle? style;
+
+ /// {@macro flutter.widgets.editableText.textAlign}
+ final TextAlign? textAlign;
+
+ /// {@macro flutter.widgets.editableText.textDirection}
+ final TextDirection? textDirection;
+
+ /// {@macro flutter.widgets.editableText.minLines}
+ final int? minLines;
+
+ /// {@macro flutter.widgets.editableText.maxLines}
+ final int? maxLines;
+
+ /// {@macro auto_size_text.locale}
+ final Locale? locale;
+
+ /// {@macro flutter.painting.textPainter.strutStyle}
+ final StrutStyle? strutStyle;
+
+ /// {@macro flutter.dart:ui.textHeightBehavior}
+ final TextHeightBehavior? textHeightBehavior;
+
+ /// {@macro flutter.painting.textPainter.textWidthBasis}
+ final TextWidthBasis? textWidthBasis;
+
+ /// {@macro flutter.widgets.editableText.textScaleFactor}
+ final double? textScaleFactor;
+
+ /// {@macro auto_size_text.wrapWords}
+ final bool? wrapWords;
+
+ /// {@macro auto_size_text.minFontSize}
+ final double? minFontSize;
+
+ /// {@macro auto_size_text.maxFontSize}
+ final double? maxFontSize;
+
+ /// {@macro auto_size_text.stepGranularity}
+ final double? stepGranularity;
+
+ /// {@macro auto_size_text.presetFontSizes}
+ final List? presetFontSizes;
+
+ @override
+ State createState() => _AutoSizeBuilderState();
+}
+
+class _AutoSizeBuilderState extends State {
+ @override
+ Widget build(BuildContext context) {
+ final defaultTextStyle = DefaultTextStyle.of(context);
+ var effectiveTextStyle = widget.style ?? defaultTextStyle.style;
+ if (widget.style == null || widget.style!.inherit) {
+ effectiveTextStyle = defaultTextStyle.style.merge(widget.style);
+ }
+ if (MediaQuery.boldTextOverride(context)) {
+ effectiveTextStyle = effectiveTextStyle.merge(
+ const TextStyle(fontWeight: FontWeight.bold),
+ );
+ }
+ if (effectiveTextStyle.fontSize == null) {
+ effectiveTextStyle = effectiveTextStyle.copyWith(fontSize: 14);
+ }
+ final text = TextSpan(
+ text: widget.text.text,
+ children: widget.text.children,
+ style: effectiveTextStyle,
+ locale: widget.text.locale,
+ );
+ return _AutoSize(
+ builder: widget.builder,
+ overflowReplacement: widget.overflowReplacement,
+ text: text,
+ textAlign:
+ widget.textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start,
+ textDirection: widget.textDirection ?? Directionality.of(context),
+ minLines: widget.minLines,
+ maxLines: widget.maxLines ?? defaultTextStyle.maxLines,
+ locale: widget.locale ?? Localizations.maybeLocaleOf(context),
+ strutStyle: widget.strutStyle,
+ textWidthBasis: widget.textWidthBasis ?? defaultTextStyle.textWidthBasis,
+ textHeightBehavior: widget.textHeightBehavior ??
+ defaultTextStyle.textHeightBehavior ??
+ DefaultTextHeightBehavior.of(context),
+ wrapWords: widget.wrapWords ?? false,
+ textScaleFactor:
+ widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
+ minFontSize: widget.minFontSize ?? 12.0,
+ maxFontSize: widget.maxFontSize ?? double.infinity,
+ stepGranularity: widget.stepGranularity ?? 1.0,
+ presetFontSizes: widget.presetFontSizes,
+ );
+ }
+}
diff --git a/lib/src/auto_size_builder/auto_size_element.dart b/lib/src/auto_size_builder/auto_size_element.dart
new file mode 100644
index 0000000..de6e683
--- /dev/null
+++ b/lib/src/auto_size_builder/auto_size_element.dart
@@ -0,0 +1,104 @@
+part of 'auto_size_builder.dart';
+
+class _AutoSizeElement extends RenderObjectElement {
+ _AutoSizeElement(_AutoSize widget) : super(widget);
+
+ @override
+ _AutoSize get widget => super.widget as _AutoSize;
+
+ @override
+ _RenderAutoSize get renderObject => super.renderObject as _RenderAutoSize;
+
+ Element? _text;
+ Element? _replacement;
+ var _overflow = false;
+
+ @override
+ void mount(Element? parent, Object? newSlot) {
+ super.mount(parent, newSlot);
+ _replacement = updateChild(null, widget.overflowReplacement, 1);
+ renderObject._buildCallback = _updateText;
+ }
+
+ @override
+ void update(_AutoSize newWidget) {
+ super.update(newWidget);
+ _replacement = updateChild(_replacement, widget.overflowReplacement, 1);
+ renderObject._buildCallback = _updateText;
+ renderObject.markNeedsBuild();
+ }
+
+ @override
+ void performRebuild() {
+ renderObject.markNeedsBuild();
+ super.performRebuild();
+ }
+
+ @override
+ void unmount() {
+ renderObject._buildCallback = null;
+ super.unmount();
+ }
+
+ void _updateText(double textScaleFactor, bool overflow) {
+ owner!.buildScope(this, () {
+ _overflow = overflow;
+ Widget built;
+ try {
+ built = widget.builder(this, textScaleFactor, overflow);
+ debugWidgetBuilderValue(widget, built);
+ } catch (e) {
+ built = ErrorWidget(e);
+ }
+ try {
+ _text = updateChild(_text, built, 0);
+ } catch (e) {
+ built = ErrorWidget(e);
+ _text = updateChild(null, built, 0);
+ }
+ });
+ }
+
+ @override
+ void insertRenderObjectChild(RenderObject child, int slot) {
+ renderObject.insert(child as RenderBox,
+ after: slot == 0 ? null : _text?.renderObject as RenderBox?);
+ }
+
+ @override
+ void moveRenderObjectChild(RenderObject child, int oldSlot, int newSlot) {
+ throw UnsupportedError('cannot move child');
+ }
+
+ @override
+ void removeRenderObjectChild(RenderObject child, int slot) {
+ renderObject.remove(child as RenderBox);
+ }
+
+ @override
+ void visitChildren(ElementVisitor visitor) {
+ if (_text != null) visitor(_text!);
+ if (_replacement != null) {
+ visitor(_replacement!);
+ }
+ }
+
+ @override
+ void debugVisitOnstageChildren(ElementVisitor visitor) {
+ if (_overflow && _replacement != null) {
+ visitor(_replacement!);
+ } else {
+ visitor(_text!);
+ }
+ }
+
+ @override
+ void forgetChild(Element child) {
+ if (child == _text) {
+ _text = null;
+ } else {
+ _replacement = null;
+ }
+ super.forgetChild(child);
+ }
+}
diff --git a/lib/src/auto_size_builder/render_auto_size.dart b/lib/src/auto_size_builder/render_auto_size.dart
new file mode 100644
index 0000000..471972a
--- /dev/null
+++ b/lib/src/auto_size_builder/render_auto_size.dart
@@ -0,0 +1,147 @@
+part of 'auto_size_builder.dart';
+
+class _AutoSizeParentData extends ParentData
+ with ContainerParentDataMixin {}
+
+class _RenderAutoSize extends RenderBox
+ with
+ ContainerRenderObjectMixin> {
+ _RenderAutoSize({required TextFitter fitter}) : _fitter = fitter;
+
+ var _overflow = false;
+ var _needsBuild = true;
+ double? _previousTextScaleFactor;
+ bool? _previousOverflow;
+ double? _longestWordWidth;
+
+ Function(double, bool)? _buildCallback;
+ set buildCallback(Function(double, bool)? buildCallback) {
+ if (_buildCallback == buildCallback) return;
+ _previousTextScaleFactor = null;
+ _buildCallback = buildCallback;
+ markNeedsLayout();
+ }
+
+ TextFitter _fitter;
+ set textFitter(TextFitter fitter) {
+ if (_fitter == fitter) return;
+ if (_fitter.text != fitter.text) {
+ _longestWordWidth = null;
+ }
+ _previousTextScaleFactor = null;
+ _fitter = fitter;
+ markNeedsLayout();
+ }
+
+ RenderBox get child => _overflow ? lastChild! : firstChild!;
+
+ bool get hasReplacement => !identical(firstChild, lastChild);
+
+ void markNeedsBuild() {
+ _needsBuild = true;
+ markNeedsLayout();
+ }
+
+ @override
+ void setupParentData(RenderObject child) {
+ if (child.parentData is! ListWheelParentData) {
+ child.parentData = _AutoSizeParentData();
+ }
+ }
+
+ @override
+ double computeMinIntrinsicWidth(double height) {
+ final result =
+ _fitter.fit(BoxConstraints.tightFor(height: height), _longestWordWidth);
+ _longestWordWidth = result.longestWordWidth;
+
+ if (result.overflow && hasReplacement) {
+ return child.getMinIntrinsicWidth(height);
+ } else {
+ return result.minIntrinsicWidth;
+ }
+ }
+
+ @override
+ double computeMaxIntrinsicWidth(double height) {
+ final result =
+ _fitter.fit(BoxConstraints.tightFor(height: height), _longestWordWidth);
+ _longestWordWidth = result.longestWordWidth;
+
+ if (result.overflow && hasReplacement) {
+ return lastChild!.getMaxIntrinsicWidth(height);
+ } else {
+ return result.maxIntrinsicWidth;
+ }
+ }
+
+ @override
+ double computeMinIntrinsicHeight(double width) {
+ final result =
+ _fitter.fit(BoxConstraints.tightFor(width: width), _longestWordWidth);
+ _longestWordWidth = result.longestWordWidth;
+
+ if (result.overflow && hasReplacement) {
+ return lastChild!.getMinIntrinsicHeight(width);
+ } else {
+ return result.size.height;
+ }
+ }
+
+ @override
+ double computeMaxIntrinsicHeight(double width) {
+ final result =
+ _fitter.fit(BoxConstraints.tightFor(width: width), _longestWordWidth);
+ _longestWordWidth = result.longestWordWidth;
+
+ if (result.overflow && hasReplacement) {
+ return lastChild!.getMaxIntrinsicHeight(width);
+ } else {
+ return result.size.height;
+ }
+ }
+
+ @override
+ void performLayout() {
+ final constraints = this.constraints;
+
+ final result = _fitter.fit(constraints, _longestWordWidth);
+ _longestWordWidth = result.longestWordWidth;
+
+ if (_needsBuild ||
+ result.scale != _previousTextScaleFactor ||
+ result.overflow != _previousOverflow) {
+ _previousTextScaleFactor = result.scale;
+ _previousOverflow = result.overflow;
+ _needsBuild = false;
+ invokeLayoutCallback(
+ (_) => _buildCallback!(result.scale, result.overflow));
+ }
+
+ _overflow = result.overflow;
+ firstChild!.layout(constraints, parentUsesSize: true);
+ if (hasReplacement) {
+ lastChild!.layout(constraints, parentUsesSize: true);
+ }
+ size = constraints.constrain(child.size);
+ }
+
+ @override
+ double? computeDistanceToActualBaseline(TextBaseline baseline) {
+ return child.computeDistanceToActualBaseline(baseline);
+ }
+
+ @override
+ bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
+ return child.hitTest(result, position: position);
+ }
+
+ @override
+ void applyPaintTransform(RenderObject child, Matrix4 transform) {}
+
+ @override
+ void paint(PaintingContext context, Offset offset) {
+ context.paintChild(child, offset);
+ }
+}
diff --git a/lib/src/auto_size_group.dart b/lib/src/auto_size_group.dart
index 32f75c3..26ecd4a 100644
--- a/lib/src/auto_size_group.dart
+++ b/lib/src/auto_size_group.dart
@@ -1,4 +1,4 @@
-part of auto_size_text;
+/*part of auto_size_text;
/// Controller to synchronize the fontSize of multiple AutoSizeTexts.
class AutoSizeGroup {
@@ -49,4 +49,4 @@ class AutoSizeGroup {
_updateFontSize(text, double.infinity);
_listeners.remove(text);
}
-}
+}*/
diff --git a/lib/src/auto_size_group_builder.dart b/lib/src/auto_size_group_builder.dart
index 23b3f24..d6c64b6 100644
--- a/lib/src/auto_size_group_builder.dart
+++ b/lib/src/auto_size_group_builder.dart
@@ -1,4 +1,4 @@
-part of auto_size_text;
+/*import 'package:flutter/material.dart';
/// A Flutter widget that provides an [AutoSizeGroup] to its builder function.
class AutoSizeGroupBuilder extends StatefulWidget {
@@ -19,5 +19,4 @@ class _AutoSizeGroupBuilderState extends State {
Widget build(BuildContext context) {
return widget.builder(context, _group);
}
-}
-
+}*/
diff --git a/lib/src/auto_size_text.dart b/lib/src/auto_size_text.dart
index ec43838..0119040 100644
--- a/lib/src/auto_size_text.dart
+++ b/lib/src/auto_size_text.dart
@@ -1,206 +1,85 @@
-part of auto_size_text;
+import 'package:auto_size_text/src/auto_size_builder/auto_size_builder.dart';
+import 'package:flutter/widgets.dart';
/// Flutter widget that automatically resizes text to fit perfectly within its
/// bounds.
///
/// All size constraints as well as maxLines are taken into account. If the text
/// overflows anyway, you should check if the parent widget actually constraints
-/// the size of this widget.
-class AutoSizeText extends StatefulWidget {
- /// Creates a [AutoSizeText] widget.
- ///
- /// If the [style] argument is null, the text will use the style from the
- /// closest enclosing [DefaultTextStyle].
- const AutoSizeText(
- String this.data, {
- Key? key,
- this.textKey,
- this.style,
- this.strutStyle,
- this.minFontSize = 12,
- this.maxFontSize = double.infinity,
- this.stepGranularity = 1,
- this.presetFontSizes,
- this.group,
- this.textAlign,
- this.textDirection,
- this.locale,
- this.softWrap,
- this.wrapWords = true,
- this.overflow,
- this.overflowReplacement,
- this.textScaleFactor,
- this.maxLines,
- this.semanticsLabel,
- }) : textSpan = null,
- super(key: key);
-
- /// Creates a [AutoSizeText] widget with a [TextSpan].
- const AutoSizeText.rich(
- TextSpan this.textSpan, {
- Key? key,
- this.textKey,
- this.style,
- this.strutStyle,
- this.minFontSize = 12,
- this.maxFontSize = double.infinity,
- this.stepGranularity = 1,
- this.presetFontSizes,
- this.group,
- this.textAlign,
- this.textDirection,
- this.locale,
- this.softWrap,
- this.wrapWords = true,
- this.overflow,
- this.overflowReplacement,
- this.textScaleFactor,
- this.maxLines,
- this.semanticsLabel,
- }) : data = null,
- super(key: key);
-
- /// Sets the key for the resulting [Text] widget.
+/// the size of this
+class AutoSizeText extends StatelessWidget {
+ /// {@template auto_size_text.textKey}
+ /// Sets the key for the resulting [Text]
///
/// This allows you to find the actual `Text` widget built by `AutoSizeText`.
+ /// It is useful if you want to be able to find the widget to modify it in
+ /// the [State.build] method of the [StatefulWidget] that `AutoSizeText` is
+ /// inserted into.
+ /// {@endtemplate}
final Key? textKey;
- /// The text to display.
- ///
- /// This will be null if a [textSpan] is provided instead.
+ /// {@macro flutter.painting.textPainter.textWidthBasis}
final String? data;
+ /// {@template auto_size_text.textSpan}
/// The text to display as a [TextSpan].
///
/// This will be null if [data] is provided instead.
+ /// {@endtemplate}
final TextSpan? textSpan;
+ /// {@template auto_size_text.style}
/// If non-null, the style to use for this text.
///
/// If the style's "inherit" property is true, the style will be merged with
/// the closest enclosing [DefaultTextStyle]. Otherwise, the style will
/// replace the closest enclosing [DefaultTextStyle].
+ /// {@endtemplate}
final TextStyle? style;
- // The default font size if none is specified.
- static const double _defaultFontSize = 14;
-
- /// The strut style to use. Strut style defines the strut, which sets minimum
- /// vertical layout metrics.
- ///
- /// Omitting or providing null will disable strut.
- ///
- /// Omitting or providing null for any properties of [StrutStyle] will result
- /// in default values being used. It is highly recommended to at least specify
- /// a font size.
- ///
- /// See [StrutStyle] for details.
+ /// {@macro flutter.painting.textPainter.strutStyle}
final StrutStyle? strutStyle;
- /// The minimum text size constraint to be used when auto-sizing text.
- ///
- /// Is being ignored if [presetFontSizes] is set.
- final double minFontSize;
-
- /// The maximum text size constraint to be used when auto-sizing text.
- ///
- /// Is being ignored if [presetFontSizes] is set.
- final double maxFontSize;
-
- /// The step size in which the font size is being adapted to constraints.
- ///
- /// The Text scales uniformly in a range between [minFontSize] and
- /// [maxFontSize].
- /// Each increment occurs as per the step size set in stepGranularity.
- ///
- /// Most of the time you don't want a stepGranularity below 1.0.
- ///
- /// Is being ignored if [presetFontSizes] is set.
- final double stepGranularity;
-
- /// Predefines all the possible font sizes.
- ///
- /// **Important:** PresetFontSizes have to be in descending order.
- final List? presetFontSizes;
-
- /// Synchronizes the size of multiple [AutoSizeText]s.
- ///
- /// If you want multiple [AutoSizeText]s to have the same text size, give all
- /// of them the same [AutoSizeGroup] instance. All of them will have the
- /// size of the smallest [AutoSizeText]
- final AutoSizeGroup? group;
-
- /// How the text should be aligned horizontally.
+ /// {@macro flutter.widgets.editableText.textAlign}
final TextAlign? textAlign;
- /// The directionality of the text.
- ///
- /// This decides how [textAlign] values like [TextAlign.start] and
- /// [TextAlign.end] are interpreted.
- ///
- /// This is also used to disambiguate how to render bidirectional text. For
- /// example, if the [data] is an English phrase followed by a Hebrew phrase,
- /// in a [TextDirection.ltr] context the English phrase will be on the left
- /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
- /// context, the English phrase will be on the right and the Hebrew phrase on
- /// its left.
- ///
- /// Defaults to the ambient [Directionality], if any.
+ /// {@macro flutter.widgets.editableText.textDirection}
final TextDirection? textDirection;
+ /// {@template auto_size_text.locale}
/// Used to select a font when the same Unicode character can
/// be rendered differently, depending on the locale.
///
/// It's rarely necessary to set this property. By default its value
/// is inherited from the enclosing app with `Localizations.localeOf(context)`.
+ ///
+ /// See [RenderParagraph.locale] for more information.
+ /// {@endtemplate}
final Locale? locale;
+ /// {@template auto_size_text.softWrap}
/// Whether the text should break at soft line breaks.
///
/// If false, the glyphs in the text will be positioned as if there was
/// unlimited horizontal space.
+ /// {@endtemplate}
final bool? softWrap;
- /// Whether words which don't fit in one line should be wrapped.
- ///
- /// If false, the fontSize is lowered as far as possible until all words fit
- /// into a single line.
- final bool wrapWords;
-
+ /// {@template auto_size_text.overflow}
/// How visual overflow should be handled.
///
/// Defaults to retrieving the value from the nearest [DefaultTextStyle] ancestor.
+ /// If there is no ancestor, [TextOverflow.clip] is used.
+ /// {@endtemplate}
final TextOverflow? overflow;
- /// If the text is overflowing and does not fit its bounds, this widget is
- /// displayed instead.
- final Widget? overflowReplacement;
-
- /// The number of font pixels for each logical pixel.
- ///
- /// For example, if the text scale factor is 1.5, text will be 50% larger than
- /// the specified font size.
- ///
- /// This property also affects [minFontSize], [maxFontSize] and [presetFontSizes].
- ///
- /// The value given to the constructor as textScaleFactor. If null, will
- /// use the [MediaQueryData.textScaleFactor] obtained from the ambient
- /// [MediaQuery], or 1.0 if there is no [MediaQuery] in scope.
+ /// {@macro flutter.widgets.editableText.textScaleFactor}
final double? textScaleFactor;
- /// An optional maximum number of lines for the text to span, wrapping if necessary.
- /// If the text exceeds the given number of lines, it will be resized according
- /// to the specified bounds and if necessary truncated according to [overflow].
- ///
- /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
- /// edge of the box.
- ///
- /// If this is null, but there is an ambient [DefaultTextStyle] that specifies
- /// an explicit number for its [DefaultTextStyle.maxLines], then the
- /// [DefaultTextStyle] value will take precedence. You can use a [RichText]
- /// widget directly to entirely override the [DefaultTextStyle].
+ /// {@macro flutter.widgets.editableText.maxLines}
final int? maxLines;
+ /// {@template auto_size_text.semanticsLabel}
/// An alternative semantics label for this text.
///
/// If present, the semantics of this widget will contain this value instead
@@ -213,246 +92,171 @@ class AutoSizeText extends StatefulWidget {
/// ```dart
/// AutoSizeText(r'$$', semanticsLabel: 'Double dollars')
/// ```
+ /// {@endtemplate}
final String? semanticsLabel;
- @override
- _AutoSizeTextState createState() => _AutoSizeTextState();
-}
-
-class _AutoSizeTextState extends State {
- @override
- void initState() {
- super.initState();
-
- widget.group?._register(this);
- }
-
- @override
- void didUpdateWidget(AutoSizeText oldWidget) {
- super.didUpdateWidget(oldWidget);
-
- if (oldWidget.group != widget.group) {
- oldWidget.group?._remove(this);
- widget.group?._register(this);
- }
- }
-
- @override
- Widget build(BuildContext context) {
- return LayoutBuilder(builder: (context, size) {
- final defaultTextStyle = DefaultTextStyle.of(context);
-
- var style = widget.style;
- if (widget.style == null || widget.style!.inherit) {
- style = defaultTextStyle.style.merge(widget.style);
- }
- if (style!.fontSize == null) {
- style = style.copyWith(fontSize: AutoSizeText._defaultFontSize);
- }
-
- final maxLines = widget.maxLines ?? defaultTextStyle.maxLines;
-
- _validateProperties(style, maxLines);
-
- final result = _calculateFontSize(size, style, maxLines);
- final fontSize = result[0] as double;
- final textFits = result[1] as bool;
-
- Widget text;
-
- if (widget.group != null) {
- widget.group!._updateFontSize(this, fontSize);
- text = _buildText(widget.group!._fontSize, style, maxLines);
- } else {
- text = _buildText(fontSize, style, maxLines);
- }
-
- if (widget.overflowReplacement != null && !textFits) {
- return widget.overflowReplacement!;
- } else {
- return text;
- }
- });
- }
-
- void _validateProperties(TextStyle style, int? maxLines) {
- assert(widget.overflow == null || widget.overflowReplacement == null,
- 'Either overflow or overflowReplacement must be null.');
- assert(maxLines == null || maxLines > 0,
- 'MaxLines must be greater than or equal to 1.');
- assert(widget.key == null || widget.key != widget.textKey,
- 'Key and textKey must not be equal.');
-
- if (widget.presetFontSizes == null) {
- assert(
- widget.stepGranularity >= 0.1,
- 'StepGranularity must be greater than or equal to 0.1. It is not a '
- 'good idea to resize the font with a higher accuracy.');
- assert(widget.minFontSize >= 0,
- 'MinFontSize must be greater than or equal to 0.');
- assert(widget.maxFontSize > 0, 'MaxFontSize has to be greater than 0.');
- assert(widget.minFontSize <= widget.maxFontSize,
- 'MinFontSize must be smaller or equal than maxFontSize.');
- assert(widget.minFontSize / widget.stepGranularity % 1 == 0,
- 'MinFontSize must be a multiple of stepGranularity.');
- if (widget.maxFontSize != double.infinity) {
- assert(widget.maxFontSize / widget.stepGranularity % 1 == 0,
- 'MaxFontSize must be a multiple of stepGranularity.');
- }
- } else {
- assert(widget.presetFontSizes!.isNotEmpty,
- 'PresetFontSizes must not be empty.');
- }
- }
+ /// {@macro flutter.dart:ui.textHeightBehavior}
+ final TextHeightBehavior? textHeightBehavior;
- List _calculateFontSize(
- BoxConstraints size, TextStyle? style, int? maxLines) {
- final span = TextSpan(
- style: widget.textSpan?.style ?? style,
- text: widget.textSpan?.text ?? widget.data,
- children: widget.textSpan?.children,
- recognizer: widget.textSpan?.recognizer,
- );
+ /// {@macro flutter.painting.textPainter.textWidthBasis}
+ final TextWidthBasis? textWidthBasis;
- final userScale =
- widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context);
-
- int left;
- int right;
-
- final presetFontSizes = widget.presetFontSizes?.reversed.toList();
- if (presetFontSizes == null) {
- final num defaultFontSize =
- style!.fontSize!.clamp(widget.minFontSize, widget.maxFontSize);
- final defaultScale = defaultFontSize * userScale / style.fontSize!;
- if (_checkTextFits(span, defaultScale, maxLines, size)) {
- return