├── gradle.properties
├── sample
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── themes.xml
│ │ │ └── colors.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── xml
│ │ │ ├── backup_rules.xml
│ │ │ └── data_extraction_rules.xml
│ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ └── drawable
│ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ └── com
│ │ │ └── idapgroup
│ │ │ └── autosizetext
│ │ │ └── sample
│ │ │ ├── ui
│ │ │ └── theme
│ │ │ │ ├── Color.kt
│ │ │ │ ├── Type.kt
│ │ │ │ └── Theme.kt
│ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
└── build.gradle
├── auto-size-text
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── idapgroup
│ │ └── autosizetext
│ │ ├── Utils.kt
│ │ └── AutoSizeText.kt
└── build.gradle
├── settings.gradle
├── .gitignore
├── LICENCE
└── README.md
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.useAndroidX=true
2 | android.enableJetifier=true
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AutoSizeText
3 |
--------------------------------------------------------------------------------
/auto-size-text/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idapgroup/AutoSizeText/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/idapgroup/autosizetext/sample/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.idapgroup.autosizetext.sample.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple80 = Color(0xFFD0BCFF)
6 | val PurpleGrey80 = Color(0xFFCCC2DC)
7 | val Pink80 = Color(0xFFEFB8C8)
8 |
9 | val Purple40 = Color(0xFF6650a4)
10 | val PurpleGrey40 = Color(0xFF625b71)
11 | val Pink40 = Color(0xFF7D5260)
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "AutoSizeText"
16 | include ':sample'
17 | include ':auto-size-text'
18 |
--------------------------------------------------------------------------------
/sample/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/idapgroup/autosizetext/sample/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.idapgroup.autosizetext.sample.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | val Typography = Typography(
10 | bodyLarge = TextStyle(
11 | fontFamily = FontFamily.Default,
12 | fontWeight = FontWeight.Normal,
13 | fontSize = 16.sp,
14 | lineHeight = 24.sp,
15 | letterSpacing = 0.5.sp
16 | )
17 | )
--------------------------------------------------------------------------------
/sample/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/auto-size-text/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | }
5 | kotlin {
6 | explicitApi()
7 | }
8 |
9 | android {
10 | namespace 'com.idapgroup.autosizetext'
11 |
12 | compileSdk 34
13 |
14 | defaultConfig {
15 | minSdkVersion 21
16 | }
17 |
18 | compileOptions {
19 | sourceCompatibility JavaVersion.VERSION_17
20 | targetCompatibility JavaVersion.VERSION_17
21 | }
22 |
23 | buildFeatures {
24 | buildConfig false
25 | compose true
26 | }
27 | composeOptions {
28 | kotlinCompilerExtensionVersion '1.5.8'
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation "androidx.compose.ui:ui:1.6.3"
34 | implementation 'androidx.compose.material3:material3:1.2.1'
35 | }
36 | ext {
37 | PUBLISH_GROUP_ID = 'com.idapgroup'
38 | PUBLISH_VERSION = '0.3.0'
39 | PUBLISH_ARTIFACT_ID = 'autosizetext-compose'
40 | }
41 |
42 | apply from: "${rootProject.projectDir}/publish/module.gradle"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle/
2 | build/
3 | local.properties
4 | publish/
5 | *.log
6 | captures/
7 | .externalNativeBuild/
8 | .cxx/
9 | *.apk
10 | output.json
11 | *.iml
12 | .idea/
13 | misc.xml
14 | deploymentTargetDropDown.xml
15 | render.experimental.xml
16 | *.jks
17 | *.keystore
18 | *.class
19 | *.jar
20 | *.war
21 | *.nar
22 | *.ear
23 | *.zip
24 | *.tar.gz
25 | *.rar
26 | *.ap_
27 | *.aab
28 | *.dex
29 | bin/
30 | gen/
31 | out/
32 | /*/build/
33 | /*/local.properties
34 | /*/out
35 | /*/*/build
36 | /*/*/production
37 | .navigation/
38 | *.ipr
39 | *~
40 | *.swp
41 | .externalNativeBuild
42 | *.iws
43 | /out/
44 | .idea/caches/
45 | .idea/libraries/
46 | .idea/shelf/
47 | .idea/workspace.xml
48 | .idea/tasks.xml
49 | .idea/.name
50 | .idea/compiler.xml
51 | .idea/copyright/profiles_settings.xml
52 | .idea/encodings.xml
53 | .idea/misc.xml
54 | .idea/modules.xml
55 | .idea/scopes/scope_settings.xml
56 | .idea/dictionaries
57 | .idea/vcs.xml
58 | .idea/jsLibraryMappings.xml
59 | .idea/datasources.xml
60 | .idea/dataSources.ids
61 | .idea/sqlDataSources.xml
62 | .idea/dynamic.xml
63 | .idea/uiDesigner.xml
64 | .idea/assetWizardSettings.xml
65 | .idea/gradle.xml
66 | .idea/jarRepositories.xml
67 | .idea/navEditor.xml
68 | .idea_modules/
69 | !/gradle/wrapper/gradle-wrapper.jar
70 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/auto-size-text/src/main/java/com/idapgroup/autosizetext/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.idapgroup.autosizetext
2 |
3 | import androidx.compose.ui.unit.TextUnit
4 |
5 | internal const val SIZE_DECREASER = 0.9f
6 |
7 | internal enum class SizeDecreasingStage(val value: Float) {
8 | Offense(0.5f),
9 | Defence(1.2f),
10 | Diplomacy(0.95f),
11 | Peace(Float.NaN);
12 | }
13 |
14 | internal fun SizeDecreasingStage?.next(didOverflowHeight: Boolean) :SizeDecreasingStage {
15 | return when {
16 | this == null -> SizeDecreasingStage.Offense
17 | this == SizeDecreasingStage.Offense && didOverflowHeight -> SizeDecreasingStage.Offense
18 | this == SizeDecreasingStage.Offense -> SizeDecreasingStage.Defence
19 | this == SizeDecreasingStage.Defence && didOverflowHeight.not() -> SizeDecreasingStage.Defence
20 | this == SizeDecreasingStage.Defence -> SizeDecreasingStage.Diplomacy
21 | this == SizeDecreasingStage.Diplomacy && didOverflowHeight -> SizeDecreasingStage.Diplomacy
22 | else -> SizeDecreasingStage.Peace
23 | }
24 | }
25 |
26 | internal data class InnerMetrics(
27 | val fontSize: TextUnit,
28 | val lineHeight: TextUnit,
29 | )
30 |
31 | internal fun coerceTextUnit(
32 | expected: TextUnit,
33 | default: TextUnit
34 | ) = if (expected != TextUnit.Unspecified) expected else default
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2023, IDAP
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.idapgroup.autosizetext.sample'
8 | compileSdk 34
9 |
10 | defaultConfig {
11 | applicationId "com.idapgroup.autosizetext.sample"
12 | minSdk 24
13 | targetSdk 34
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_17
24 | targetCompatibility JavaVersion.VERSION_17
25 | }
26 | kotlinOptions {
27 | jvmTarget = '17'
28 | }
29 | buildFeatures {
30 | compose true
31 | }
32 | composeOptions {
33 | kotlinCompilerExtensionVersion '1.5.8'
34 | }
35 | packagingOptions {
36 | resources {
37 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
38 | }
39 | }
40 | }
41 |
42 | dependencies {
43 | implementation 'androidx.core:core-ktx:1.12.0'
44 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
45 | implementation 'androidx.activity:activity-compose:1.8.2'
46 | implementation "androidx.compose.ui:ui:1.6.3"
47 | implementation "androidx.compose.ui:ui-tooling-preview:1.6.3"
48 | implementation 'androidx.compose.material3:material3:1.2.1'
49 |
50 | //Most useful dependency
51 | implementation 'com.idapgroup:autosizetext-compose:0.3.0'
52 | // implementation(project(":auto-size-text"))
53 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/idapgroup/autosizetext/sample/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.idapgroup.autosizetext.sample.ui.theme
2 |
3 | import android.app.Activity
4 | import android.os.Build
5 | import androidx.compose.foundation.isSystemInDarkTheme
6 | import androidx.compose.material3.MaterialTheme
7 | import androidx.compose.material3.darkColorScheme
8 | import androidx.compose.material3.dynamicDarkColorScheme
9 | import androidx.compose.material3.dynamicLightColorScheme
10 | import androidx.compose.material3.lightColorScheme
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.SideEffect
13 | import androidx.compose.ui.graphics.toArgb
14 | import androidx.compose.ui.platform.LocalContext
15 | import androidx.compose.ui.platform.LocalView
16 | import androidx.core.view.ViewCompat
17 |
18 | private val DarkColorScheme = darkColorScheme(
19 | primary = Purple80,
20 | secondary = PurpleGrey80,
21 | tertiary = Pink80
22 | )
23 |
24 | private val LightColorScheme = lightColorScheme(
25 | primary = Purple40,
26 | secondary = PurpleGrey40,
27 | tertiary = Pink40
28 | )
29 |
30 | @Composable
31 | fun AutoSizeTextTheme(
32 | darkTheme: Boolean = isSystemInDarkTheme(),
33 | dynamicColor: Boolean = true,
34 | content: @Composable () -> Unit
35 | ) {
36 | val colorScheme = when {
37 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
38 | val context = LocalContext.current
39 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
40 | }
41 | darkTheme -> DarkColorScheme
42 | else -> LightColorScheme
43 | }
44 | MaterialTheme(
45 | colorScheme = colorScheme,
46 | typography = Typography,
47 | content = content
48 | )
49 | }
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AutoSizeText
2 |
3 | AutoSizeText component for `Material3 Android Compose`.
4 |
5 | ## Setup
6 | Please, check that repositories has `mavenCentral()`
7 | ```groovy
8 | repositories {
9 | mavenCentral()
10 | }
11 | ```
12 | Add to your module next dependency:
13 |
14 | 
15 | ```groovy
16 | dependencies {
17 | implementation 'com.idapgroup:autosizetext-compose:'
18 | }
19 | ```
20 | `Note:` Do not forget to add compose dependencies 🙃
21 |
22 | ## Usage sample
23 | `AutoSizeText` has all the properties that original `Text` has plus additional properties:
24 | + `minFontSize` - specifies min value for font size. If min value reached but text still overflows, `overflow` parameter will be used. If `minFontSize` is not specified, the text size will scale down until fit the borders and `overflow` param will be ignored.
25 | + `keepLineHeight` - specifies line height changes. Default value `false` means that line height will be changed in aspect ratio to the default `fontSize` and `lineHeight`. `true` means that provided `lineHeight` will be unchanged.
26 |
27 | Also remember that `AutoSizeText` will not have effect if text has no borders (`wraps the content`).
28 |
29 | For reach the autosizing effect, uou can strict the `maxLines` param
30 | ```kotlin
31 | AutoSizeText(
32 | text = longText,
33 | maxLines = 2,
34 | fontSize = 14.sp,
35 | lineHeight = 16.sp,
36 | minFontSize = 12.sp
37 | )
38 | ```
39 | or set the `height` for the modifier.
40 | ```kotlin
41 | AutoSizeText(
42 | modifier = Modifier.height(60.dp),
43 | text = longText,
44 | fontSize = 40.sp,
45 | lineHeight = 42.sp,
46 | keepLineHeight = true,
47 | overflow = TextOverflow.Ellipsis,
48 | )
49 | Box(modifier = Modifier.height(40.dp)) {
50 | AutoSizeText(
51 | text = longText,
52 | fontSize = 40.sp,
53 | lineHeight = 42.sp,
54 | keepLineHeight = false,
55 | )
56 | }
57 | ```
58 | For more info, please check the `sample` module.
59 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/idapgroup/autosizetext/sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.idapgroup.autosizetext.sample
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.foundation.layout.Arrangement
7 | import androidx.compose.foundation.layout.Box
8 | import androidx.compose.foundation.layout.Column
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.height
11 | import androidx.compose.material3.MaterialTheme
12 | import androidx.compose.material3.Surface
13 | import androidx.compose.runtime.Composable
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.text.font.FontWeight
16 | import androidx.compose.ui.text.style.TextOverflow
17 | import androidx.compose.ui.tooling.preview.Preview
18 | import androidx.compose.ui.unit.dp
19 | import androidx.compose.ui.unit.sp
20 | import com.idapgroup.autosizetext.AutoSizeText
21 | import com.idapgroup.autosizetext.sample.ui.theme.AutoSizeTextTheme
22 |
23 | private const val longText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer " +
24 | "feugiat, ligula a volutpat dictum, velit est cursus erat, non eleifend dui leo " +
25 | "nec diam. Vestibulum aliquet accumsan mollis. Praesent pellentesque lacinia " +
26 | "pretium. Ut nec convallis tortor. Duis quis venenatis justo. Integer convallis " +
27 | "ipsum dolor, in dignissim diam malesuada at. Praesent ac lacus neque. Praesent " +
28 | "imperdiet ultricies purus sagittis accumsan. Vivamus dignissim orci ut metus " +
29 | "tristique porttitor. In vel auctor ipsum."
30 |
31 | class MainActivity : ComponentActivity() {
32 | override fun onCreate(savedInstanceState: Bundle?) {
33 | super.onCreate(savedInstanceState)
34 | setContent {
35 | AutoSizeTextTheme {
36 | Surface(
37 | modifier = Modifier.fillMaxSize(),
38 | color = MaterialTheme.colorScheme.background
39 | ) {
40 | Greeting()
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
47 | @Composable
48 | fun Greeting() {
49 | Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
50 | AutoSizeText(
51 | text = longText,
52 | fontSize = 14.sp,
53 | lineHeight = 15.sp,
54 | minFontSize = 12.sp
55 | )
56 | AutoSizeText(
57 | text = longText,
58 | maxLines = 8,
59 | fontSize = 20.sp,
60 | lineHeight = 20.sp,
61 | fontWeight = FontWeight.ExtraBold,
62 | minFontSize = 8.sp
63 | )
64 | AutoSizeText(
65 | modifier = Modifier.height(100.dp),
66 | text = longText,
67 | fontSize = 40.sp,
68 | )
69 | AutoSizeText(
70 | modifier = Modifier.height(100.dp),
71 | text = longText,
72 | fontSize = 1000.sp,
73 | lineHeight = 40.sp,
74 | keepLineHeight = true,
75 | )
76 | Box(modifier = Modifier.height(40.dp)) {
77 | AutoSizeText(
78 | text = longText,
79 | fontSize = 1000.sp,
80 | lineHeight = 1020.sp,
81 | )
82 | }
83 |
84 | Box(modifier = Modifier.height(50.dp)) {
85 | AutoSizeText(
86 | text = longText,
87 | fontSize = 40.sp,
88 | lineHeight = 42.sp,
89 | keepLineHeight = true,
90 | minFontSize = 38.sp,
91 | overflow = TextOverflow.Ellipsis,
92 | )
93 | }
94 | }
95 | }
96 |
97 | @Preview(showBackground = true)
98 | @Composable
99 | fun DefaultPreview() {
100 | AutoSizeTextTheme {
101 | Greeting()
102 | }
103 | }
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/auto-size-text/src/main/java/com/idapgroup/autosizetext/AutoSizeText.kt:
--------------------------------------------------------------------------------
1 | package com.idapgroup.autosizetext
2 |
3 | import androidx.compose.material3.LocalTextStyle
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.runtime.getValue
7 | import androidx.compose.runtime.mutableStateOf
8 | import androidx.compose.runtime.remember
9 | import androidx.compose.runtime.setValue
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.draw.drawWithContent
12 | import androidx.compose.ui.graphics.Color
13 | import androidx.compose.ui.text.TextLayoutResult
14 | import androidx.compose.ui.text.TextStyle
15 | import androidx.compose.ui.text.font.FontFamily
16 | import androidx.compose.ui.text.font.FontStyle
17 | import androidx.compose.ui.text.font.FontWeight
18 | import androidx.compose.ui.text.style.TextAlign
19 | import androidx.compose.ui.text.style.TextDecoration
20 | import androidx.compose.ui.text.style.TextOverflow
21 | import androidx.compose.ui.unit.TextUnit
22 |
23 | /**
24 | * future releases:
25 | * 1. Support maxFontSize
26 | * 2. Add types: Maximisation, Minimization, Balanced
27 | */
28 |
29 | /**
30 | * Resizeable Text element that contains all the default behavior and description
31 | * that you can find in [Text].
32 | * Minimization applied only by height. If you want to reach result,
33 | * you need to set [maxLines] or your container should have fixed size, otherwise [fontSize] will
34 | * be used.
35 | *
36 | * Extra parameters:
37 | * @param minFontSize - Allows you to specify minimum allowed font size for text. If [minFontSize]
38 | * reached but text still overflows, you can use default [overflow] param.
39 | * @param keepLineHeight - Allows you to control line height decreasing. If you want to make your
40 | * line height unchanged provide `true`. By default `false` means that line height will be
41 | * decreased by default aspect ratio from provided values.
42 | * Example:
43 | * [fontSize] = 12.sp; [lineHeight] = 24.sp.
44 | * In that case, if [keepLineHeight] = false, [lineHeight] will be always 2 times bigger
45 | * than [fontSize].
46 | * If [keepLineHeight] = true, [lineHeight] will have always 24.sp.
47 | */
48 | @Composable
49 | public fun AutoSizeText(
50 | text: String,
51 | modifier: Modifier = Modifier,
52 | minFontSize: TextUnit = TextUnit.Unspecified,
53 | color: Color = Color.Unspecified,
54 | fontSize: TextUnit = TextUnit.Unspecified,
55 | fontStyle: FontStyle? = null,
56 | fontWeight: FontWeight? = null,
57 | fontFamily: FontFamily? = null,
58 | letterSpacing: TextUnit = TextUnit.Unspecified,
59 | textDecoration: TextDecoration? = null,
60 | textAlign: TextAlign? = null,
61 | lineHeight: TextUnit = TextUnit.Unspecified,
62 | softWrap: Boolean = true,
63 | maxLines: Int = Int.MAX_VALUE,
64 | minLines: Int = 1,
65 | onTextLayout: (TextLayoutResult) -> Unit = {},
66 | style: TextStyle = LocalTextStyle.current,
67 | overflow: TextOverflow = TextOverflow.Clip,
68 | keepLineHeight: Boolean = false,
69 | ) {
70 | val defaultFontSize = coerceTextUnit(
71 | expected = fontSize,
72 | default = style.fontSize
73 | )
74 | val defaultLineHeight = coerceTextUnit(
75 | expected = lineHeight,
76 | default = style.lineHeight
77 | )
78 |
79 | val ratio = defaultFontSize.value / defaultLineHeight.value
80 |
81 | var overriddenMetrics by remember(key1 = text) {
82 | mutableStateOf(
83 | InnerMetrics(
84 | fontSize = defaultFontSize,
85 | lineHeight = defaultLineHeight
86 | )
87 | )
88 | }
89 | var textReadyToDraw by remember(key1 = text) {
90 | mutableStateOf(false)
91 | }
92 | var decreasingStage: SizeDecreasingStage? by remember(key1 = text) {
93 | mutableStateOf(null)
94 | }
95 |
96 | Text(
97 | modifier = modifier.drawWithContent {
98 | if (textReadyToDraw) {
99 | drawContent()
100 | }
101 | },
102 | text = text,
103 | color = color,
104 | textAlign = textAlign,
105 | fontSize = overriddenMetrics.fontSize,
106 | fontFamily = fontFamily,
107 | fontStyle = fontStyle,
108 | fontWeight = fontWeight,
109 | letterSpacing = letterSpacing,
110 | textDecoration = textDecoration,
111 | lineHeight = overriddenMetrics.lineHeight,
112 | style = style,
113 | maxLines = maxLines,
114 | minLines = minLines,
115 | softWrap = softWrap,
116 | overflow = if (textReadyToDraw) overflow else TextOverflow.Clip,
117 | onTextLayout = { result ->
118 | if (textReadyToDraw) {
119 | onTextLayout(result)
120 | return@Text
121 | }
122 | if (minFontSize == TextUnit.Unspecified || overriddenMetrics.fontSize > minFontSize) {
123 | if (result.didOverflowHeight.not() && decreasingStage == null) {
124 | textReadyToDraw = true
125 | onTextLayout(result)
126 | return@Text
127 | }
128 |
129 | decreasingStage = decreasingStage.next(result.didOverflowHeight)
130 | if (decreasingStage == SizeDecreasingStage.Peace) {
131 | textReadyToDraw = true
132 | } else {
133 | val correctedFontSize = overriddenMetrics.fontSize.times(decreasingStage!!.value)
134 | val correctedLineHeight =
135 | if (keepLineHeight) lineHeight else correctedFontSize.div(ratio)
136 | overriddenMetrics = overriddenMetrics.copy(
137 | fontSize = correctedFontSize,
138 | lineHeight = correctedLineHeight
139 | )
140 | }
141 | } else {
142 | if (overriddenMetrics.fontSize <= minFontSize) {
143 | val minLineHeight = if (keepLineHeight) lineHeight else minFontSize.div(ratio)
144 | overriddenMetrics = InnerMetrics(
145 | fontSize = minFontSize,
146 | lineHeight = minLineHeight
147 | )
148 | textReadyToDraw = true
149 | }
150 | }
151 | onTextLayout(result)
152 | },
153 | )
154 | }
155 |
--------------------------------------------------------------------------------