This repository has been archived by the owner on Jul 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Text.kt
262 lines (255 loc) · 11.9 KB
/
Text.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.material3
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Paragraph
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.TextUnit
/**
* High level element that displays text and provides semantics / accessibility information.
*
* The default [style] uses the [LocalTextStyle] provided by the [MaterialTheme] / components. If
* you are setting your own style, you may want to consider first retrieving [LocalTextStyle],
* and using [TextStyle.copy] to keep any theme defined attributes, only modifying the specific
* attributes you want to override.
*
* For ease of use, commonly used parameters from [TextStyle] are also present here. The order of
* precedence is as follows:
* - If a parameter is explicitly set here (i.e, it is _not_ `null` or [TextUnit.Unspecified]),
* then this parameter will always be used.
* - If a parameter is _not_ set, (`null` or [TextUnit.Unspecified]), then the corresponding value
* from [style] will be used instead.
*
* Additionally, for [color], if [color] is not set, and [style] does not have a color, then
* [LocalContentColor] will be used.
*
* @param text the text to be displayed
* @param modifier the [Modifier] to be applied to this layout node
* @param color [Color] to apply to the text. If [Color.Unspecified], and [style] has no color set,
* this will be [LocalContentColor].
* @param fontSize the size of glyphs to use when painting the text. See [TextStyle.fontSize].
* @param fontStyle the typeface variant to use when drawing the letters (e.g., italic).
* See [TextStyle.fontStyle].
* @param fontWeight the typeface thickness to use when painting the text (e.g., [FontWeight.Bold]).
* @param fontFamily the font family to be used when rendering the text. See [TextStyle.fontFamily].
* @param letterSpacing the amount of space to add between each letter.
* See [TextStyle.letterSpacing].
* @param textDecoration the decorations to paint on the text (e.g., an underline).
* See [TextStyle.textDecoration].
* @param textAlign the alignment of the text within the lines of the paragraph.
* See [TextStyle.textAlign].
* @param lineHeight line height for the [Paragraph] in [TextUnit] unit, e.g. SP or EM.
* See [TextStyle.lineHeight].
* @param overflow how visual overflow should be handled.
* @param 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. If [softWrap] is false,
* [overflow] and TextAlign may have unexpected effects.
* @param maxLines 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 truncated according to
* [overflow] and [softWrap]. If it is not null, then it must be greater than zero.
* @param onTextLayout callback that is executed when a new text layout is calculated. A
* [TextLayoutResult] object that callback provides contains paragraph information, size of the
* text, baselines and other details. The callback can be used to add additional decoration or
* functionality to the text. For example, to draw selection around the text.
* @param style style configuration for the text such as color, font, line height etc.
*/
@Composable
fun Text(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current
) {
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current
}
}
// NOTE(text-perf-review): It might be worthwhile writing a bespoke merge implementation that
// will avoid reallocating if all of the options here are the defaults
val mergedStyle = style.merge(
TextStyle(
color = textColor,
fontSize = fontSize,
fontWeight = fontWeight,
textAlign = textAlign,
lineHeight = lineHeight,
fontFamily = fontFamily,
textDecoration = textDecoration,
fontStyle = fontStyle,
letterSpacing = letterSpacing
)
)
BasicText(
text,
modifier,
mergedStyle,
onTextLayout,
overflow,
softWrap,
maxLines,
)
}
/**
* High level element that displays text and provides semantics / accessibility information.
*
* The default [style] uses the [LocalTextStyle] provided by the [MaterialTheme] / components. If
* you are setting your own style, you may want to consider first retrieving [LocalTextStyle],
* and using [TextStyle.copy] to keep any theme defined attributes, only modifying the specific
* attributes you want to override.
*
* For ease of use, commonly used parameters from [TextStyle] are also present here. The order of
* precedence is as follows:
* - If a parameter is explicitly set here (i.e, it is _not_ `null` or [TextUnit.Unspecified]),
* then this parameter will always be used.
* - If a parameter is _not_ set, (`null` or [TextUnit.Unspecified]), then the corresponding value
* from [style] will be used instead.
*
* Additionally, for [color], if [color] is not set, and [style] does not have a color, then
* [LocalContentColor] will be used.
*
* @param text the text to be displayed
* @param modifier the [Modifier] to be applied to this layout node
* @param color [Color] to apply to the text. If [Color.Unspecified], and [style] has no color set,
* this will be [LocalContentColor].
* @param fontSize the size of glyphs to use when painting the text. See [TextStyle.fontSize].
* @param fontStyle the typeface variant to use when drawing the letters (e.g., italic).
* See [TextStyle.fontStyle].
* @param fontWeight the typeface thickness to use when painting the text (e.g., [FontWeight.Bold]).
* @param fontFamily the font family to be used when rendering the text. See [TextStyle.fontFamily].
* @param letterSpacing the amount of space to add between each letter.
* See [TextStyle.letterSpacing].
* @param textDecoration the decorations to paint on the text (e.g., an underline).
* See [TextStyle.textDecoration].
* @param textAlign the alignment of the text within the lines of the paragraph.
* See [TextStyle.textAlign].
* @param lineHeight line height for the [Paragraph] in [TextUnit] unit, e.g. SP or EM.
* See [TextStyle.lineHeight].
* @param overflow how visual overflow should be handled.
* @param 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. If [softWrap] is false,
* [overflow] and TextAlign may have unexpected effects.
* @param maxLines 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 truncated according to
* [overflow] and [softWrap]. If it is not null, then it must be greater than zero.
* @param inlineContent a map storing composables that replaces certain ranges of the text, used to
* insert composables into text layout. See [InlineTextContent].
* @param onTextLayout callback that is executed when a new text layout is calculated. A
* [TextLayoutResult] object that callback provides contains paragraph information, size of the
* text, baselines and other details. The callback can be used to add additional decoration or
* functionality to the text. For example, to draw selection around the text.
* @param style style configuration for the text such as color, font, line height etc.
*/
@Composable
fun Text(
text: AnnotatedString,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
inlineContent: Map<String, InlineTextContent> = mapOf(),
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current
) {
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current
}
}
// NOTE(text-perf-review): It might be worthwhile writing a bespoke merge implementation that
// will avoid reallocating if all of the options here are the defaults
val mergedStyle = style.merge(
TextStyle(
color = textColor,
fontSize = fontSize,
fontWeight = fontWeight,
textAlign = textAlign,
lineHeight = lineHeight,
fontFamily = fontFamily,
textDecoration = textDecoration,
fontStyle = fontStyle,
letterSpacing = letterSpacing
)
)
BasicText(
text,
modifier,
mergedStyle,
onTextLayout,
overflow,
softWrap,
maxLines,
inlineContent
)
}
/**
* CompositionLocal containing the preferred [TextStyle] that will be used by [Text] components by
* default. To set the value for this CompositionLocal, see [ProvideTextStyle] which will merge any
* missing [TextStyle] properties with the existing [TextStyle] set in this CompositionLocal.
*
* @see ProvideTextStyle
*/
val LocalTextStyle = compositionLocalOf(structuralEqualityPolicy()) { TextStyle.Default }
// TODO(b/156598010): remove this and replace with fold definition on the backing CompositionLocal
/**
* This function is used to set the current value of [LocalTextStyle], merging the given style
* with the current style values for any missing attributes. Any [Text] components included in
* this component's [content] will be styled with this style unless styled explicitly.
*
* @see LocalTextStyle
*/
@Composable
fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit) {
val mergedStyle = LocalTextStyle.current.merge(value)
CompositionLocalProvider(LocalTextStyle provides mergedStyle, content = content)
}