Text và Typography
Hiển thị và xử lý text là một trong những tác vụ phổ biến nhất trong UI. Bài này hướng dẫn chi tiết cách làm việc với Text trong Compose.
1. Text cơ bản
Phần tiêu đề “1. Text cơ bản”Hiển thị Text đơn giản
Phần tiêu đề “Hiển thị Text đơn giản”@Composablefun BasicTextExamples() { Column { Text("Hello World")
Text( text = "Styled Text", color = Color.Blue, fontSize = 20.sp, fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic, letterSpacing = 2.sp ) }}Các properties của Text
Phần tiêu đề “Các properties của Text”| Property | Mô tả | Ví dụ |
|---|---|---|
text |
Nội dung text | "Hello" |
color |
Màu chữ | Color.Blue |
fontSize |
Kích thước chữ | 16.sp |
fontWeight |
Độ đậm | FontWeight.Bold |
fontStyle |
Kiểu chữ | FontStyle.Italic |
fontFamily |
Font family | FontFamily.Serif |
letterSpacing |
Khoảng cách chữ | 2.sp |
textDecoration |
Underline, line-through | TextDecoration.Underline |
textAlign |
Căn lề | TextAlign.Center |
lineHeight |
Chiều cao dòng | 24.sp |
maxLines |
Số dòng tối đa | 2 |
overflow |
Xử lý khi tràn | TextOverflow.Ellipsis |
2. TextStyle và Typography
Phần tiêu đề “2. TextStyle và Typography”Sử dụng TextStyle
Phần tiêu đề “Sử dụng TextStyle”@Composablefun TextStyleExample() { Text( text = "Custom Style", style = TextStyle( color = Color.DarkGray, fontSize = 18.sp, fontWeight = FontWeight.Medium, fontFamily = FontFamily.SansSerif, lineHeight = 24.sp, letterSpacing = 0.5.sp ) )}Sử dụng MaterialTheme typography
Phần tiêu đề “Sử dụng MaterialTheme typography”@Composablefun MaterialTypography() { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Text("Display Large", style = MaterialTheme.typography.displayLarge) Text("Headline Medium", style = MaterialTheme.typography.headlineMedium) Text("Title Large", style = MaterialTheme.typography.titleLarge) Text("Body Large", style = MaterialTheme.typography.bodyLarge) Text("Label Medium", style = MaterialTheme.typography.labelMedium) }}Merge TextStyles
Phần tiêu đề “Merge TextStyles”@Composablefun MergedStyle() { val baseStyle = MaterialTheme.typography.bodyLarge
Text( text = "Custom merged style", style = baseStyle.copy( color = Color.Blue, fontWeight = FontWeight.Bold ) )}3. AnnotatedString - Rich Text
Phần tiêu đề “3. AnnotatedString - Rich Text”Styled spans
Phần tiêu đề “Styled spans”@Composablefun StyledSpans() { Text( buildAnnotatedString { append("Normal text ")
withStyle(SpanStyle(color = Color.Red)) { append("Red text ") }
withStyle(SpanStyle( fontWeight = FontWeight.Bold, textDecoration = TextDecoration.Underline )) { append("Bold underlined") } } )}Paragraph styles
Phần tiêu đề “Paragraph styles”@Composablefun ParagraphStyles() { Text( buildAnnotatedString { withStyle(ParagraphStyle(textAlign = TextAlign.Center)) { append("Centered paragraph\n") }
withStyle(ParagraphStyle( textIndent = TextIndent(firstLine = 16.sp), lineHeight = 24.sp )) { append("This paragraph has first-line indentation and custom line height.") } } )}4. Clickable Text và Links
Phần tiêu đề “4. Clickable Text và Links”ClickableText
Phần tiêu đề “ClickableText”@Composablefun ClickableTextExample() { val annotatedString = buildAnnotatedString { append("Click ") pushStringAnnotation(tag = "URL", annotation = "https://google.com") withStyle(SpanStyle(color = Color.Blue, textDecoration = TextDecoration.Underline)) { append("here") } pop() append(" to visit Google") }
ClickableText( text = annotatedString, onClick = { offset -> annotatedString.getStringAnnotations(tag = "URL", start = offset, end = offset) .firstOrNull()?.let { annotation -> // Open URL println("Clicked: ${annotation.item}") } } )}Sử dụng LinkAnnotation (Compose 1.7+)
Phần tiêu đề “Sử dụng LinkAnnotation (Compose 1.7+)”@Composablefun ModernLinkExample() { val annotatedString = buildAnnotatedString { append("Read our ")
withLink( LinkAnnotation.Url( url = "https://example.com/terms", styles = TextLinkStyles( style = SpanStyle(color = Color.Blue), hoveredStyle = SpanStyle(textDecoration = TextDecoration.Underline) ) ) ) { append("Terms of Service") } }
Text(annotatedString)}5. TextField - Input text
Phần tiêu đề “5. TextField - Input text”Basic TextField
Phần tiêu đề “Basic TextField”@Composablefun BasicTextFieldExample() { var text by remember { mutableStateOf("") }
TextField( value = text, onValueChange = { text = it }, label = { Text("Enter name") }, placeholder = { Text("John Doe") }, singleLine = true )}OutlinedTextField
Phần tiêu đề “OutlinedTextField”@Composablefun OutlinedExample() { var email by remember { mutableStateOf("") } var isError by remember { mutableStateOf(false) }
OutlinedTextField( value = email, onValueChange = { email = it isError = !it.contains("@") }, label = { Text("Email") }, leadingIcon = { Icon(Icons.Default.Email, null) }, trailingIcon = { if (isError) { Icon(Icons.Default.Warning, null, tint = Color.Red) } }, isError = isError, supportingText = { if (isError) { Text("Invalid email format", color = MaterialTheme.colorScheme.error) } } )}Password TextField
Phần tiêu đề “Password TextField”@Composablefun PasswordTextField() { var password by remember { mutableStateOf("") } var visible by remember { mutableStateOf(false) }
OutlinedTextField( value = password, onValueChange = { password = it }, label = { Text("Password") }, singleLine = true, visualTransformation = if (visible) VisualTransformation.None else PasswordVisualTransformation(), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), trailingIcon = { IconButton(onClick = { visible = !visible }) { Icon( if (visible) Icons.Default.Visibility else Icons.Default.VisibilityOff, null ) } } )}6. Keyboard Options và Actions
Phần tiêu đề “6. Keyboard Options và Actions”KeyboardOptions
Phần tiêu đề “KeyboardOptions”@Composablefun KeyboardOptionsExample() { var phone by remember { mutableStateOf("") }
TextField( value = phone, onValueChange = { phone = it }, label = { Text("Phone") }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Phone, // Bàn phím số điện thoại imeAction = ImeAction.Done // Nút Done ) )}Các KeyboardType
Phần tiêu đề “Các KeyboardType”| Type | Mô tả |
|---|---|
Text |
Default |
Number |
Chỉ số |
Phone |
Số điện thoại |
Email |
|
Password |
Password |
NumberPassword |
PIN |
Decimal |
Số thập phân |
Uri |
URL |
KeyboardActions
Phần tiêu đề “KeyboardActions”@Composablefun FormFields() { val focusManager = LocalFocusManager.current var name by remember { mutableStateOf("") } var email by remember { mutableStateOf("") }
Column { TextField( value = name, onValueChange = { name = it }, label = { Text("Name") }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), keyboardActions = KeyboardActions( onNext = { focusManager.moveFocus(FocusDirection.Down) } ) )
TextField( value = email, onValueChange = { email = it }, label = { Text("Email") }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions( onDone = { focusManager.clearFocus() } ) ) }}7. Custom Fonts
Phần tiêu đề “7. Custom Fonts”Thêm font vào resources
Phần tiêu đề “Thêm font vào resources”Đặt font files vào res/font/:
res/└── font/ ├── roboto_regular.ttf ├── roboto_bold.ttf └── roboto_italic.ttfTạo FontFamily
Phần tiêu đề “Tạo FontFamily”val RobotoFamily = FontFamily( Font(R.font.roboto_regular, FontWeight.Normal), Font(R.font.roboto_bold, FontWeight.Bold), Font(R.font.roboto_italic, FontWeight.Normal, FontStyle.Italic))
@Composablefun CustomFontText() { Text( text = "Custom Font", fontFamily = RobotoFamily, fontWeight = FontWeight.Bold )}Downloadable Fonts
Phần tiêu đề “Downloadable Fonts”val provider = GoogleFont.Provider( providerAuthority = "com.google.android.gms.fonts", providerPackage = "com.google.android.gms", certificates = R.array.com_google_android_gms_fonts_certs)
val fontFamily = FontFamily( Font( googleFont = GoogleFont("Lobster"), fontProvider = provider ))8. Text Selection
Phần tiêu đề “8. Text Selection”SelectionContainer
Phần tiêu đề “SelectionContainer”@Composablefun SelectableText() { SelectionContainer { Column { Text("This text can be selected") Text("This text can also be selected") } }}DisableSelection
Phần tiêu đề “DisableSelection”@Composablefun MixedSelection() { SelectionContainer { Column { Text("Selectable") DisableSelection { Text("Not selectable") } Text("Selectable again") } }}9. Text overflow và max lines
Phần tiêu đề “9. Text overflow và max lines”@Composablefun TextOverflowExamples() { val longText = "This is a very long text that will overflow..."
Column { Text( text = longText, maxLines = 1, overflow = TextOverflow.Ellipsis // ... )
Text( text = longText, maxLines = 2, overflow = TextOverflow.Clip // Cắt bỏ )
Text( text = longText, maxLines = 1, overflow = TextOverflow.Visible // Hiển thị tràn ) }}10. BasicTextField - Custom Design
Phần tiêu đề “10. BasicTextField - Custom Design”Khi cần tùy chỉnh hoàn toàn giao diện TextField:
@Composablefun CustomTextField() { var text by remember { mutableStateOf("") }
BasicTextField( value = text, onValueChange = { text = it }, modifier = Modifier .fillMaxWidth() .background(Color.LightGray, RoundedCornerShape(8.dp)) .padding(16.dp), textStyle = TextStyle(fontSize = 16.sp), decorationBox = { innerTextField -> Box { if (text.isEmpty()) { Text("Placeholder...", color = Color.Gray) } innerTextField() // Actual text field } } )}📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| Component | Mục đích |
|---|---|
Text |
Hiển thị text |
TextField |
Input với Material Design |
OutlinedTextField |
Input với outline style |
BasicTextField |
Input để custom hoàn toàn |
AnnotatedString |
Rich text với multiple styles |
ClickableText |
Text với click handlers |
SelectionContainer |
Cho phép select text |
Best Practices
Phần tiêu đề “Best Practices”- Dùng MaterialTheme.typography cho consistency
- Sử dụng sp cho fontSize (scales with user preferences)
- Handle keyboard actions cho form fields
- Provide visual feedback cho TextField errors
- Dùng BasicTextField khi cần custom design hoàn toàn