文字是所有使用者介面的核心,Jetpack Compose 可讓系統以更簡單的方式顯示或撰寫文字。Compose 可以善用其建構塊的組合,這意味著您不需要覆寫屬性和方法,也不需要擴充大型類別,即可擁有特定可組合項設計以及按照您想要的方式執行的邏輯。
Compose 提供了 BasicText
和 BasicTextField
基本元素,做為顯示文字及處理使用者輸入內容的基本方式。Compose 在更高級別提供 Text
和 TextField
,這是根據質感設計準則所構成的組件。建議您使用它們,因為這樣一來,Android 使用者才能獲得良好的外觀和風格,同時提供其他選項簡化自訂程序,而且完全不須編寫大量的程式碼。
顯示文字
顯示文字最基本的方法,就是以 String
做為引數的方式使用 Text
組件:
@Composable
fun SimpleText() {
Text("Hello World")
}
顯示資源中的文字
我們建議您使用字串資源,而非針對 Text
值進行硬式編碼,因為這樣您可以和 Android 檢視畫面共用相同的字串,以及做好應用程式國際化準備工作:
@Composable
fun StringResourceText() {
Text(stringResource(R.string.hello_world))
}
樣式文字
Text
組件提供多個選用參數,可用以設定其內容樣式。以下我們列出涵蓋最常見的文字使用方式參數。若要查看 Text
的所有參數,建議您查看 Compose 文字原始碼。
每當您設定其中一個參數,您就會套用樣式至整個文字值。如果您需要在同一行或同一段落中套用多種樣式,請參閱多種內嵌樣式一節。
變更文字顏色
@Composable
fun BlueText() {
Text("Hello World", color = Color.Blue)
}
變更文字大小
@Composable
fun BigText() {
Text("Hello World", fontSize = 30.sp)
}
將文字設定為斜體
使用 fontStyle
參數將文字設為斜體 (或設定另一個 FontStyle
)。
@Composable
fun ItalicText() {
Text("Hello World", fontStyle = FontStyle.Italic)
}
將文字設定為粗體
使用 fontWeight
參數將文字設為粗體 (或設定其他 FontWeight
)。
@Composable
fun BoldText() {
Text("Hello World", fontWeight = FontWeight.Bold)
}
文字對齊
textAlign
參數允許您在 Text
組件途徑區中設定文字的對齊方式。
根據預設,Text
會根據內容值選擇自然文字對齊方式:
Text
容器的左側邊緣為由左至右的字母,例如拉丁文、斯拉夫文或韓文Text
容器的右側邊緣為由右至左的字母,例如阿拉伯文或希伯來文
@Preview(showBackground = true)
@Composable
fun CenterText() {
Text("Hello World", textAlign = TextAlign.Center,
modifier = Modifier.width(150.dp))
}
若要手動設定 Text
組件的文字對齊方式,建議個別使用 TextAlign.Start
和 TextAlign.End
,而不要使用 TextAlign.Left
和 TextAlign.Right
,因為它們會根據偏好語言文字方向解析 Text
組件的右側邊緣。舉例來說,TextAlign.End
會對齊法文的右側以及阿拉伯文的左側,但無論使用何種字母,TextAlign.Right
都會對齊右側。
陰影
您可以透過 style
參數設定 TextStyle
類型的物件,並設定多個參數,例如陰影。Shadow
會接收陰影色彩、偏移值或與 Text
的相對位置,以及模糊半徑 (即模糊程度)。
@Preview(showBackground = true)
@Composable
fun TextShadow() {
val offset = Offset(5.0f, 10.0f)
Text(
text = "Hello world!",
style = TextStyle(
fontSize = 24.sp,
shadow = Shadow(
color = Color.Blue,
offset = offset,
blurRadius = 3f
)
)
)
}
使用字型
Text
有 fontFamily
參數,可設定在組件中使用的字型。系統預設包含 Serif、Sans Serif、等寬和草寫字型系列:
@Composable
fun DifferentFonts() {
Column {
Text("Hello World", fontFamily = FontFamily.Serif)
Text("Hello World", fontFamily = FontFamily.SansSerif)
}
}
您可以使用 fontFamily
屬性搭配 res/font
資料夾中定義的自訂字型和字體:
字型資料夾的圖形描述" class="l10n-absolute-url-src screenshot" l10n-attrs-original-order="src,alt,width,class" src="https://developer.android.com/static/images/jetpack/compose/text-font-folder.png" width="400" />
以下範例說明如何根據這些字型檔案以及使用 Font
函式定義 fontFamily
:
val firaSansFamily = FontFamily(
Font(R.font.firasans_light, FontWeight.Light),
Font(R.font.firasans_regular, FontWeight.Normal),
Font(R.font.firasans_italic, FontWeight.Normal, FontStyle.Italic),
Font(R.font.firasans_medium, FontWeight.Medium),
Font(R.font.firasans_bold, FontWeight.Bold)
)
最後,您可以將此 fontFamily
傳遞給 Text
的組件。由於 fontFamily
可包含不同的粗細,因此您可以手動設定 fontWeight
,選取適當的文字粗細:
Column {
Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
Text(
..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal,
fontStyle = FontStyle.Italic
)
Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}
若要瞭解如何在整個應用程式中設定字型樣式,請參閱主題說明文件。
文字中的多種樣式
如要在相同的 Text
組件中設定不同樣式,您必須使用可使用任意註解樣式加上註解的字串 AnnotatedString
。
AnnotatedString
是包含以下的資料類別:
Text
值SpanStyleRange
的List
,等同於文字值內位置範圍的內嵌樣式ParagraphStyleRange
的List
,用於指定文字對齊方式、文字方向、行高和文字縮排樣式
TextStyle
用於 Text
組件中,其中 SpanStyle
和 ParagraphStyle
適用於 AnnotatedString
。
SpanStyle
和 ParagraphStyle
的差異在於 ParagraphStyle
可以套用至整個段落,SpanStyle
則可套用字元層級。如果部分文字有加上 ParagraphStyle
標記,則該部分會與其餘部分分開,如同在開頭和結尾部分加上換行字元。
AnnotatedString
具有類型安全建構工具,可讓您輕鬆建立:buildAnnotatedString
。
@Composable
fun MultipleStylesInText() {
Text(
buildAnnotatedString {
withStyle(style = SpanStyle(color = Color.Blue)) {
append("H")
}
append("ello ")
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
append("W")
}
append("orld")
}
)
}
我們能夠以相同方式設定 ParagraphStyle
:
@Composable
fun ParagraphStyle() {
Text(
buildAnnotatedString {
withStyle(style = ParagraphStyle(lineHeight = 30.sp)) {
withStyle(style = SpanStyle(color = Color.Blue)) {
append("Hello\n")
}
withStyle(
style = SpanStyle(
fontWeight = FontWeight.Bold,
color = Color.Red
)
) {
append("World\n")
}
append("Compose")
}
}
)
}
行數上限
如要限制 Text
組件的顯示行數,請設定 maxLines
參數:
@Composable
fun LongText() {
Text("hello ".repeat(50), maxLines = 2)
}
文字溢位
限制長文字時,您可能需要指定 TextOverflow
;這只有在顯示的文字遭到截斷時才會顯示。如要執行此操作,請設定 textOverflow
參數:
@Composable
fun OverflowedText() {
Text("Hello Compose ".repeat(50), maxLines = 2, overflow = TextOverflow.Ellipsis)
}
includeFontPadding 和 lineHeight API
includeFontPadding
是舊版屬性,並會根據文字第一行頂端和最後一行的字型指標新增額外的邊框間距。在 Compose 1.2.0 中,includeFontPadding 預設為 True。
建議您從 Compose 1.2.0 版本中使用已淘汰的 API PlatformTextStyle
,將 includeFontPadding
設為 False (這會移除額外邊框間距),並進一步調整文字。
設定 lineHeight
的功能並非全新功能,這項功能自 Android Q 起即可使用。您可以使用 lineHeight
參數將 Text
設定為 lineHeight
,這會在每行文字中分配行高。然後,您就可以使用新的 LineHeightStyle API
,進一步設定文字在聊天室中對齊的方式,並移除空白字元。
建議使用文字單位「em」(相對字型大小),而不使用「sp」(縮放像素) 來調整 lineHeight
,以提升精確度。如要進一步瞭解如何選取適當的文字單元,請參閱此處的說明文件。

@Composable
fun AlignedText() {
Text(
text = myText,
style = LocalTextStyle.current.merge(
TextStyle(
lineHeight = 2.5.em,
platformStyle = PlatformTextStyle(
includeFontPadding = false
),
lineHeightStyle = LineHeightStyle(
alignment = LineHeightStyle.Alignment.Center,
trim = LineHeightStyle.Trim.None
)
)
)
)
}
除了調整 lineHeight
,您現在可以透過LineHeightStyle
實驗性 API 使用設定來進一步使文字置中和設定樣式:LineHeightStyle.Alignment
和 LineHeightStyle.Trim
(includeFontPadding
必須設定為 False,剪輯才能正常運作)。對齊和剪輯會將文字行間測量到的空間,更妥善地分配至所有行,包括單行文字和文字區塊的頂行文字。
LineHeightStyle.Alignment
定義如何利用行高所提供的空間將行對齊。在每行中,您可以將文字與頂端、底部、置中或依比例對齊。LineHeightStyle.Trim
則允許您保留或刪除文字第一行頂部和最後一行底部的額外空間,這些空間是由任何 lineHeight
和對齊調整所產生。以下範例顯示了置中對齊時 (LineHeightStyle.Alignment.Center
),多行文字搭配各種 LineHeightStyle.Trim
設定的樣式。
![]() |
![]() |
LineHeightStyle.Trim.None | LineHeightStyle.Trim.Both |
![]() |
![]() |
LineHeightStyle.Trim.FirstLineTop | LineHeightStyle.Trim.LastLineBottom |
請參閱「修正 Compose 文字中的字型邊框間距」網誌文章,進一步瞭解這項變更的前後內容,並瞭解 includeFontPadding 在 View 系統中的運作方式,以及 Compose 的變更和新的 LineHeightStyle
API。
主題設定
如要使用應用程式主題設定文字樣式,請參閱主題說明文件。
使用者互動
Jetpack Compose 可在 Text
中進行精細的互動。文字選取功能現在更具彈性,並且可以在可組合項的版面配置中完成。文字中的使用者互動與其他可組合項的版面配置不同,因為您無法在一部分 Text
可組合項中新增修飾詞。本節重點介紹各種可於啟用使用者互動的 API。
選取文字
根據預設,可組合項是無法選取的,也就是說,在預設情況下,使用者無法選取及複製應用程式中的文字。如要啟用文字選取功能,必須使用 SelectionContainer
可組合項包裝文字元素:
@Composable
fun SelectableText() {
SelectionContainer {
Text("This text is selectable")
}
}
您可能需要針對可選取區域的特定部分停用選取功能。如要執行此操作,您必須使用 DisableSelection
組件納入無法選取的部分:
@Composable
fun PartiallySelectableText() {
SelectionContainer {
Column {
Text("This text is selectable")
Text("This one too")
Text("This one as well")
DisableSelection {
Text("But not this one")
Text("Neither this one")
}
Text("But again, you can select this one")
Text("And this one too")
}
}
}
取得點擊文字的位置
如要監聽 Text
上的點擊,您可以新增 clickable
輔助鍵。但是,如果您想在 Text
可組合項中取得點選位置,在對文字的不同部分執行不同動作的情況下,就必須改用 ClickableText
:
@Composable
fun SimpleClickableText() {
ClickableText(
text = AnnotatedString("Click Me"),
onClick = { offset ->
Log.d("ClickableText", "$offset -th character is clicked.")
}
)
}
附帶備註的點擊
當使用者按一下 Text
組件時,您可能需要在部分 Text
值中附加其他資訊,例如附加至特定字詞,以便在瀏覽器中開啟的網址:若要執行此操作,您必須附加註解,以標記 (String
)、項目 (String
) 和文字範圍做為參數。使用 AnnotatedString
即可依標記或文字範圍篩選這些註解。範例如下:
@Composable
fun AnnotatedClickableText() {
val annotatedText = buildAnnotatedString {
append("Click ")
// We attach this *URL* annotation to the following content
// until `pop()` is called
pushStringAnnotation(tag = "URL",
annotation = "https://developer.android.com")
withStyle(style = SpanStyle(color = Color.Blue,
fontWeight = FontWeight.Bold)) {
append("here")
}
pop()
}
ClickableText(
text = annotatedText,
onClick = { offset ->
// We check if there is an *URL* annotation attached to the text
// at the clicked position
annotatedText.getStringAnnotations(tag = "URL", start = offset,
end = offset)
.firstOrNull()?.let { annotation ->
// If yes, we log its value
Log.d("Clicked URL", annotation.item)
}
}
)
}
輸入並修改文字
TextField
可讓使用者輸入及修改文字。TextField
實作分為兩個層級:
TextField
為質感設計實作。建議您選擇此實作程序,因為符合質感設計準則:BasicTextField
可讓使用者透過硬體或螢幕鍵盤編輯文字,但無法提供提示或預留位置等裝飾。
@Composable
fun SimpleFilledTextFieldSample() {
var text by remember { mutableStateOf("Hello") }
TextField(
value = text,
onValueChange = { text = it },
label = { Text("Label") }
)
}
@Composable
fun SimpleOutlinedTextFieldSample() {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Label") }
)
}
設定文字欄位樣式
TextField
和 BasicTextField
會共用許多常見的參數以進行自訂。TextField
原始碼內提供 TextField
的完整清單。這份清單僅列舉部分有用參數的內容:
singleLine
maxLines
textStyle
@Composable
fun StyledTextField() {
var value by remember { mutableStateOf("Hello\nWorld\nInvisible") }
TextField(
value = value,
onValueChange = { value = it },
label = { Text("Enter text") },
maxLines = 2,
textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
modifier = Modifier.padding(20.dp)
)
}
如果設計需要 Material TextField 或 OutlineTextField,建議使用 BasicTextField
而非 TextField
。然而,如果建構的設計不需要使用材質規格的裝飾,則應使用 BasicTextField
。
鍵盤選項
TextField
可讓您設定鍵盤設定選項 (例如鍵盤配置);或是啟用自動更正功能 (如果鍵盤有支援)。如果螢幕鍵盤不符合此處提供的選項,則可能無法保證某些選項可以使用。以下是支援的鍵盤選項清單:
capitalization
autoCorrect
keyboardType
imeAction
格式設定
TextField
可讓您為輸入值設定 VisualTransformation
,例如將密碼中的字符更換為 *
,或是在信用卡號碼中每隔 4 位數字插入一個連字號:
@Composable
fun PasswordTextField() {
var password by rememberSaveable { mutableStateOf("") }
TextField(
value = password,
onValueChange = { password = it },
label = { Text("Enter password") },
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
}
您可以在 VisualTransformSamples 原始碼中找到更多範例。
清理輸入
編輯文字的常見工作是移除前置字元,或在每次變更文字時轉換輸入字串。
做為模型,您應該假設每個 onValueChange
都可進行任意和大規模編輯。舉例來說,如果使用者使用自動更正功能,並以表情符號取代字詞或其他智慧編輯功能,就可能發生這種情況。為了正確處理這種情況,請在編寫任何轉換邏輯時假設,傳遞至 onValueChange
的目前文字與將被傳遞至 onValueChange
的前一個或下一個值無關。
如要實作不允許內容開頭為零的文字欄位,可以在每次值變更時移除所有開頭的零。
@Composable
fun NoLeadingZeroes() {
var input by rememberSaveable { mutableStateOf("") }
TextField(
value = input,
onValueChange = { newText ->
input = newText.trimStart { it == '0' }
}
)
}
如要在清除文字時控制遊標位置,請使用 TextField
的 TextFieldValue
超載做為狀態的一部分。
可下載的字型
從 Compose 1.2-alpha07 開始,您可以使用 Compose 應用程式中的可下載字型 API,以非同步方式下載 Google 字型,然後在應用程式中使用。
目前暫不支援自訂提供者提供的可下載字型。
透過程式輔助方式使用可下載字型
如要透過程式輔助方式下載字型,請執行下列步驟:
- 新增依附元件:
Groovy
dependencies { ... implementation "androidx.compose.ui:ui-text-google-fonts:1.3.0" }
Kotlin
dependencies { ... implementation("androidx.compose.ui:ui-text-google-fonts:1.3.0") }
- 使用 Google Fonts 的憑證初始化
GoogleFont.Provider
。@OptIn(ExperimentalTextApi::class) val provider = GoogleFont.Provider( providerAuthority = "com.google.android.gms.fonts", providerPackage = "com.google.android.gms", certificates = R.array.com_google_android_gms_fonts_certs )
供應者收到的參數包括:- Google Fonts 的字型提供者授權。
- 用於辨識供應者身分的字型供應者套件。
- 憑證的雜湊組合,用於驗證供應者的身分。您可以在 JetChat 範例應用程式的
font_certs.xml
檔案中找到 Google Fonts 供應者所需的雜湊。
ExperimentalTextApi
註解,才能在您的應用程式中使用可下載的字型 API。 - 定義
FontFamily
,如下所示:import androidx.compose.ui.text.googlefonts.GoogleFont import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.googlefonts.Font val fontName = GoogleFont("Lobster Two") val fontFamily = FontFamily( Font(googleFont = fontName, fontProvider = provider) )
您可以個別使用FontWeight
和FontStyle
查詢字型使用的其他參數 (例如粗細和樣式):import androidx.compose.ui.text.googlefonts.GoogleFont import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.googlefonts.Font val fontName = GoogleFont("Lobster Two") val fontFamily = FontFamily( Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold, style = FontStyle.Italic) )
- 設定要在文字可組合函式中使用的
FontFamily
,這樣就大功告成了!Text( fontFamily = fontFamily, text = "Hello World!" )
FontFamily
定義字型。val MyTypography = Typography( body1 = TextStyle( fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = ... ), body2 = TextStyle( fontFamily = fontFamily, fontWeight = FontWeight.Bold, letterSpacing = ... ), h4 = TextStyle( fontFamily = fontFamily, fontWeight = FontWeight.SemiBold ... ), ...
然後,請將字型設為應用程式的主題:MyAppTheme( typography = MyTypography ) { ...
如需在 Compose 中搭配 Material3 實作可下載字型的應用程式範例,請務必查看 JetChat 範例應用程式。
備用字型
您可以決定字型的備用鏈,以防字型無法正確下載。舉例來說,如果您設定了可下載的字型,如下所示:
import androidx.compose.ui.text.googlefonts.Font val fontName = GoogleFont("Lobster Two") val fontFamily = FontFamily( Font(googleFont = fontName, fontProvider = provider), Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold) )
您可以同時定義兩種粗細的字型預設值,如下所示:
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.googlefonts.Font val fontName = GoogleFont("Lobster Two") val fontFamily = FontFamily( Font(googleFont = fontName, fontProvider = provider), Font(resId = R.font.my_font_regular), Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold), Font(resId = R.font.my_font_regular_bold, weight = FontWeight.Bold) )
確認您新增的是正確的匯入項目。
定義這種 FontFamily
會建立一個 FontFamily
,其中包含兩個鏈結,每種粗細一個。載入機制會嘗試先解析線上字型,然後再處理本機 R.font
資源資料夾中的字型。
偵錯實作
為協助您確認字型下載是否正確,您可以定義偵錯協同程式處理常式。您的控點可提供字型無法以非同步方式載入時的處理方式。
首先,請建立 CoroutineExceptionHandler
。
val handler = CoroutineExceptionHandler { _, throwable ->
// process the Throwable
Log.e(TAG, "There has been an issue: ", throwable)
}
然後再將其傳遞至 createFontFamilyResolver
方法,讓解析器使用新的處理常式:
CompositionLocalProvider(
LocalFontFamilyResolver provides createFontFamilyResolver(LocalContext.current, handler)
) {
Column {
Text(
text = "Hello World!",
style = MaterialTheme.typography.body1
)
}
}
您也可以使用提供者的 isAvailableOnDevice
API 來測試提供者是否可用,以及憑證設定是否正確無誤。若要執行此操作,您可以呼叫 isAvailableOnDevice
方法,若提供者設定錯誤,則會傳回 false。
val context = LocalContext.current
LaunchedEffect(Unit) {
if (provider.isAvailableOnDevice(context)) {
Log.d(TAG, "Success!")
}
}
注意事項
Google Fonts 需要數個月的時間才能在 Android 上提供新字型。當字型在 fonts.google.com 中新增後,需要一段時間才可透過可下載字型 API 提供 (在檢視系統或 Compose 中)。使用 IllegalStateException
載入的新字型可能無法在應用程式中載入。為了協助開發人員判斷該錯誤,並與其他類型的字型載入錯誤進行比較,我們已針對 Compose 使用這裡的變更新增例外狀況訊息。