在看完 UI 外層的 Window
及 MenuBar
後,接下來持續往內看其他元件。在刻 UI 時,最常需要處理的應該就是「文字」吧?今天的耕讀筆記就以 Text
相關的元件為主軸,研究一下其使用及設定方式。
Text
元件要在 UI 上顯示文字,不論是一句或是多行,都可以使用 Text
元件。雖然 Text
元件有高達十六個參數可以設定,但除了 text
(設定要顯示的文字)參數外,其餘全部都有預設值,所以要在 UI 上放文字只需要非常精簡的一段程式碼:
// 宣告一個文字元件
Text("Hello, World")
// 元件完整參數示意
Text(
text = "...",
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
)
若是要微調樣式裡的細節,可以透過以上這些參數來做設定:
text
:設定要顯示的文字。modifier
:調整 Text
屬性。color
:設定文字顏色。fontSize
:設定文字大小。fontStyle
:設定文字風格,如斜體。fontWeight
:設定文字粗細。fontFamily
:設定文字字體。letterSpacing
:設定文字的字元間距。textDecoration
:設定文字裝飾,如底線。textAlign
:設定文字對齊方式。lineHeight
:設定文句的行距。overflow
:設定當文字字數超過文字框範圍時的效果。softWrap
:設定文字是否折行,預設為 true
。maxLines
:設定文字框行數上限。onTextLayout
:設定監聽當文字框發生變化時的 Event Handler。style
:文字樣式設定。這個設定與上面各屬性重疊,開發者可以選擇偏好的樣式設定方式。其實 Text
的基礎樣式已遵守 Material Design 的設計原則,若你有客製化的需求,可以用更低階的 BasicText
再做延伸。
color
)想要調整文字顏色,可以傳入 androidx.compose.ui.graphics.Color
實例當參數。設定 Color
時,可直接傳入 32-bit ARGB 顏色整數值,如 0xFF00FFFF
,或是直接用預設色板,如 Color.Cyan
。
Text(
text = "...",
color = Color(0xFF00FFFF)
)
Text(
text = "...",
color = Color.Cyan
)
Color
類別的預設色板有:
Color.Black
:黑色。Color.DarkGray
:深灰色。Color.Gray
:灰色。Color.LightGray
:亮灰色。Color.White
:白色。Color.Red
:紅色。Color.Green
:綠色。Color.Blue
:藍色。Color.Yellow
:黃色。Color.Cyan
:青色。Color.Magenta
:品紅色。Color.Transparent
:透明。fontSize
)想要調整文字大小,可直接設定 20.sp
這種較為精簡的語法,或是傳入 androidx.compose.ui.unit.TextUnit
實例當參數。在設定 TextUnit
時,需傳入型別為 Float 的數值(如 20F
)及設定 TextUnitType
(如 TextUnitType.Sp
)。在使用 TextUnit
時,由於用到 Experimental API,記得要標記 @OptIn(ExperimentalUnitApi::class)
Annotation。
Text(
text = "...",
fontSize = 20.sp
)
Text(
text = "...",
fontSize = TextUnit(20F, TextUnitType.Sp)
)
fontStyle
)fontStyle
只有兩種風格:一般(Normal
)及斜體(Italic
)。想要設定文字風格,可傳入 androidx.compose.ui.text.font.FontStyle
實例當參數,傳入 0
就是一般、傳入 1
就是斜體。或是直接用 Preset 更具可讀性。
Text(
text = "...",
fontStyle = FontStyle(0) // 等同 FontStyle.Normal
)
Text(
text = "...",
fontStyle = FontStyle.Italic
)
fontWeight
)想要調整文字粗細,可以傳入 androidx.compose.ui.text.font.FontWeight
實例當參數。設定 FontWeight
時,可直接傳入整數值,或是直接用 Preset。
Text(
text = "...",
fontWeight = FontWeight(1000)
)
Text(
text = "...",
fontWeight = FontWeight.Thin
)
FontWeight
類別的 Preset 有:
Thin
ExtraLight
Light
Normal
Medium
SemiBold
Bold
ExtraBold
Black
W100
、W200
、W300
到 W900
fontFamily
)想要設定文字字體,傳入 androidx.compose.ui.text.font.FontFamily
的 Preset 即可。
Text(
text = "...",
fontFamily = FontFamily.Default
)
Text(
text = "...",
fontFamily = FontFamily.Monospace
)
FontFamily
類別的 Preset 有:
Default
SansSerif
Serif
Monospace
Cursive
textDecoration
)想要設定文字裝飾,傳入 androidx.compose.ui.text.style.TextDecoration
的 Preset 即可。
Text(
text = "...",
textDecoration = TextDecoration.Underline
)
Text(
text = "...",
textDecoration = TextDecoration.LineThrough
)
TextDecoration
類別的 Preset 有:
None
:沒有文字裝飾。Underline
:底線。LineThrough
:刪除線。textAlign
)想要設定文字對齊方式,傳入 androidx.compose.ui.text.style.TextAlign
的 Preset 即可。
Text(
text = "...",
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Left,
)
Text(
text = "...",
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
)
Text(
text = "...",
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Right
)
在上面的例子裡,傳入 Modifier
參數讓文字框撐大到跟 Window
一樣寬,才能看到文字對齊的視覺效果。關於 Modifier
的用法,之後會有再另外深入研究,現階段先暫時 Copy & Paste 使用即可。TextAlign
類別的 Preset 有:
Left
:置左對齊。Right
:置右對齊。Center
:置中對齊。Justify
:左右對齊。Start
:從頭對齊。End
:從尾對齊。letterSpacing
、lineHeight
、overflow
、softWrap
、maxLines
)許多時候 UI 顯示的不會只是一小段文字,而是一整篇文章,這時要控制的就是一整段文字,可以把 Text
視為文字框來做更多文字排版的設定。
Text(
text = "...",
letterSpacing = 5.sp,
lineHeight = 10.sp,
overflow = TextOverflow.Ellipsis,
softWrap = true,
maxLines = 3,
)
在上面的範例裡,letterSpacing
及 lineHeight
都是傳入 TextUnit
類別,用 數值 + sp
設定即可。softWrap
設定了當文字超過文字框的範圍時要不要折行,maxLines
是與 overflow
搭配,由 maxLines
決定文字框的高度是幾行,若文字字數超過文字框所能顯示的行數,則由 overflow
決定超過時要怎麼顯示。
TextOverflow
類別的顯示方式共有:
Clip
:強制截斷。Ellipsis
:超過的部份截斷,並在結尾加上 ...
。Visible
:強制顯示,文字會超出文字框破壞版面。AnnotatedString
排出混合多種樣式及標記的文字在排版大量文字時,比方說一篇文章,往往會需要混合多種樣式,比方說標題、粗體、底線,甚至想要標記文字裡面的超連結,使用單純的 String 並無法滿足需求。若遇到這樣的情境,我們可以使用 Compose 的 AnnotatedString
。
AnnotatedString
是一個 Data Class,除了儲存文字內容外,還包含 SpanStyle
和 ParagraphStyle
的 Range
清單。SpanStyle
用於標記在字串的文字樣式,ParagraphStyle
用於標記字串的段落樣式,Range
則是確定各字串的範圍。我們可以使用 buildAnnotatedString()
函式,以 DSL 的方式建立 AnnotatedString
,並用 append
增加文字進字串,withStyle
則可用於指定文字或段落的樣式。
另外,我們還可以用 pushStringAnnotation()
搭配 tag
及 annotation
參數來增加標記直到呼叫 pop()
結束,這些標記可以用來與點擊事件搭配做互動。
Text(
text = buildAnnotatedString {
withStyle(
style = SpanStyle(
color = Color.Black,
fontSize = 30.sp,
)
) {
append("Click ")
}
pushStringAnnotation(
tag = "URL",
annotation = "https://kotlin.tips"
)
withStyle(
style = SpanStyle(
color = Color.Blue,
fontSize = 30.sp,
fontWeight = FontWeight.Bold,
textDecoration = TextDecoration.Underline
)
) {
append("HERE")
}
pop()
}
)
預設 Text
對點擊事件是沒有反應的,若需要做出如超連結的文字點擊互動,可以用 ClickedText
。在使用 ClickedText
元件時,傳入的 text
參數就得是 AnnotatedString
,再綁定 onClick
事件,就可以做出超連結的效果:
val annotatedText = buildAnnotatedString { /* ... */ }
ClickableText(
text = annotatedText,
onClick = { offset ->
annotatedText.getStringAnnotations(
tag = "URL",
start = offset,
end = offset
).firstOrNull()?.let { annotation ->
println("Go to ${annotation.item}")
}
}
)
Compose 元件是可以互相堆疊與組合使用的,由於許多地方都會用到 Text
元件(比方說在 Button
裡),因此預設 Text
是不能被選取的(防止按鈕上的文字也會被選取,影響其他按鈕互動)。不過在一些情境下,比方說顯示一整篇的文章時,我們會需要讓 Text
裡的文字可以被選取。
要讓 Text
的文字可以被選取,只要在外層加一個 SelectionContainer
即可,只要被這個容器包住的 Text
元件就能夠被選取。反之,若不想元件內的 Text
被選取,則可用 DisableSelection
包住。甚至這兩個容器還可以互動包夾混用:
Column {
SelectionContainer {
Column {
Text("I'm SELECTABLE")
DisableSelection {
Text(
text = "I'm NOT selectable"
)
}
Text("I'm SELECTABLE")
}
}
Text(
text = "I'm NOT selectable"
)
}
從上例可以看出,單獨的 Text
是不能被選取的,而被 SelectionContainer
包住的 Text
則可以,但在 SelectionContainer
容器裡被 DisableSelection
包住的 Text
也是不能被選取的。透過這兩個容器的運用,就可以明確界定哪些文字可選取,哪些不行了。
這跟本 Text
的百科全書吧! 推~
因為還在初學,所以只好地毯式的掃過一次各元件,進階的還要靠你多分享了 ?