Văn bản trong Compose

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Văn bản là phần chính của mọi giao diện người dùng và Jetpack Compose giúp cho việc hiển thị hoặc soạn thảo văn bản dễ dàng hơn. Compose tận dụng cấu tạo các khối xây dựng cơ bản, có nghĩa là bạn không cần phải ghi đè các thuộc tính và các phương thức hoặc mở rộng các lớp lớn để có một thiết kế thành phần kết hợp cụ thể và logic hoạt động theo cách bạn muốn.

Cũng giống như nền tảng của công cụ, Compose cung cấp một BasicTextBasicTextField là các khung để hiển thị văn bản và xử lý dữ liệu nhập của người dùng. Ở cấp độ cao hơn, Compose cung cấp TextTextField, là những thành phần kết hợp tuân theo các nguyên tắc của Material Design. Hệ thống khuyến khích sử dụng vì chúng có giao diện phù hợp cho người dùng trên Android và bao gồm các tuỳ chọn khác để đơn giản hoá chế độ tuỳ chỉnh mà không cần viết nhiều mã code.

Hiển thị văn bản

Cách cơ bản nhất để hiển thị văn bản là sử dụng thành phần kết hợp Text với String như một đối số:

@Composable
fun SimpleText() {
    Text("Hello World")
}

Dòng chữ "Hello World" màu đen thuần tuý

Hiển thị văn bản trong tài nguyên

Hệ thống khuyến nghị bạn sử dụng tài nguyên chuỗi thay vì mã cứng các giá trị Text, vì bạn có thể chia sẻ cùng một chuỗi với Android Views cũng như chuẩn bị đưa ứng dụng của bạn ra thị trường quốc tế:

@Composable
fun StringResourceText() {
    Text(stringResource(R.string.hello_world))
}

Tạo kiểu văn bản

Thành phần kết hợp Text có nhiều thông số tuỳ chọn để tạo kiểu cho nội dung. Dưới đây là danh sách các thông số bao gồm hầu hết các trường hợp phổ biến nhất có sử dụng văn bản. Để xem tất cả các thông số của Text, bạn nên xem phần Mã nguồn văn bản trong Compose.

Bất cứ khi nào bạn cài đặt một trong các thông số này, tức là bạn đang áp dụng một kiểu cho toàn bộ giá trị văn bản. Nếu bạn cần áp dụng nhiều kiểu trong cùng một dòng hoặc đoạn, hãy xem mục nhiều kiểu trong cùng dòng.

Thay đổi màu văn bản

@Composable
fun BlueText() {
    Text("Hello World", color = Color.Blue)
}

Dòng chữ "Hello World" màu xanh lam

Thay đổi kích cỡ văn bản

@Composable
fun BigText() {
  Text("Hello World", fontSize = 30.sp)
}

Dòng chữ "Hello World" có kích thước lớn hơn

Tạo chữ in nghiêng

Sử dụng tham số fontStyle để in nghiêng văn bản (hoặc đặt FontStyle khác).

@Composable
fun ItalicText() {
  Text("Hello World", fontStyle = FontStyle.Italic)
}

Dòng chữ "Hello World" kiểu in nghiêng

Làm cho văn bản in đậm

Dùng thông số fontWeight để in đậm văn bản (hoặc đặt một giá trị khác FontWeight).

@Composable
fun BoldText() {
    Text("Hello World", fontWeight = FontWeight.Bold)
}

Dòng chữ "Hello World" kiểu in đậm

Căn chỉnh văn bản

Thông số textAlign cho phép cài đặt độ căn chỉnh của văn bản trong một phạm vi nền tảng thành phần kết hợp Text.

Theo mặc định, Text sẽ chọn cách căn chỉnh văn bản tự nhiên tuỳ thuộc vào giá trị nội dung nó:

  • Cạnh trái của vùng chứa Text dành cho các bảng chữ cái từ trái sang phải, chẳng hạn như chữ La tinh, Cyrillic hoặc Hangul
  • Cạnh phải của vùng chứa Text dành cho các bảng chữ cái từ phải sang trái, chẳng hạn như chữ Ả Rập hoặc chữ Do Thái
@Preview(showBackground = true)
@Composable
fun CenterText() {
    Text("Hello World", textAlign = TextAlign.Center,
                modifier = Modifier.width(150.dp))
}

Dòng chữ "Hello World" được căn giữa phần tử chứa chúng

Nếu bạn muốn đặt chế độ căn chỉnh văn bản theo cách thủ công cho một thành phần kết hợp Text, hãy ưu tiên sử dụng TextAlign.StartTextAlign.End thay vì TextAlign.LeftTextAlign.Right, vì chúng sẽ phân giải ở cạnh bên phải của thành phần kết hợp Text tuỳ vào hướng văn bản ngôn ngữ được ưu tiên. Ví dụ: TextAlign.End căn chỉnh ở bên phải cho văn bản tiếng Pháp và bên trái cho văn bản tiếng Ả Rập, nhưng TextAlign.Right sẽ căn chỉnh bên phải cho dù bạn sử dụng bảng chữ cái nào.

Bóng

Thông số style cho phép đặt một đối tượng thuộc loại TextStyle và định cấu hình nhiều thông số, chẳng hạn như bóng. Shadow nhận được màu cho bóng đổ, độ lệch hoặc vị trí màu nằm dọc trên Text và bán kính làm mờ trông như thế nào.

@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
            )
        )
    )
}

Dòng chữ "Hello World" có bóng đổ màu xanh dương

Thiết lập phông chữ

Text có một thông số fontFamily để cho phép cài đặt phông chữ được dùng trong thành phần kết hợp. Theo mặc định, bộ phông chữ serif, sans-serif, phông chữ đơn cách và chữ viết tay được bao gồm:

@Composable
fun DifferentFonts() {
    Column {
        Text("Hello World", fontFamily = FontFamily.Serif)
        Text("Hello World", fontFamily = FontFamily.SansSerif)
    }
}

Dòng chữ "Hello World" trong hai phông chữ khác nhau, sử dụng và không sử dụng phông chữ có serif

Bạn có thể sử dụng thuộc tính fontFamily để làm việc với các phông chữ và kiểu chữ tuỳ chỉnh đã xác định trong thư mục res/font:

Mô tả đồ hoạ của thư mục phông chữ res > trong môi trường phát triển

Ví dụ này cho thấy cách bạn xác định fontFamily dựa trên các tệp phông chữ đó và sử dụng hàm Font:

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)
)

Cuối cùng, bạn có thể chuyển fontFamily sang thành phần kết hợp Text. Bởi vì fontFamily có thể bao gồm các trọng số khác nhau, nên bạn có thể đặt fontWeight theo cách thủ công để chọn trọng số phù hợp cho văn bản của mình:

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)
}

Dòng chữ "Hello World" theo một vài kiểu và loại trọng số khác nhau

Để tìm hiểu cách đặt kiểu chữ trong toàn bộ ứng dụng, hãy xem tài liệu về giao diện.

Nhiều kiểu trong một văn bản

Để đặt các kiểu khác nhau trong cùng một thành phần kết hợpText bạn phải sử dụng một chuỗi AnnotatedString, có thể được chú thích theo kiểu tuỳ ý

AnnotatedString là một lớp dữ liệu chứa:

  • Một giá trị Text
  • List của SpanStyleRange, tương đương với định kiểu trong cùng dòng với phạm vi vị trí trong giá trị văn bản
  • List của ParagraphStyleRange, xác định cách căn chỉnh văn bản, câu lệnh văn bản, chiều cao dòng và kiểu thụt lề văn bản

TextStyle được sử dụng trong thành phần kết hợp Text , trong khi SpanStyleParagraphStyle là để sử dụng trong AnnotatedString.

Sự khác biệt giữa SpanStyleParagraphStyle là có thể áp dụng ParagraphStyle cho cả một đoạn văn, còn SpanStyle có thể áp dụng ở cấp ký tự. Khi một phần văn bản được đánh dấu bằng ParagraphStyle, phần đó sẽ được tách ra khỏi phần còn lại như thể nó có nguồn cấp dữ liệu dòng ở đầu và cuối.

AnnotatedStringtrình tạo loại an toàn để dễ dàng tạo: 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")
        }
    )
}

Dòng chữ "Hello World" với một số thay đổi về kiểu trong cùng dòng; H có màu xanh lam và W có màu đỏ và chữ đậm

Chúng ta có thể đặt ParagraphStyle theo cách tương tự:

@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")
            }
        }
    )
}

Ba đoạn văn theo ba kiểu khác nhau: Xanh dương, đỏ và chữ đậm, và đen thuần tuý

Số dòng tối đa

Để giới hạn số dòng hiển thị trong một thành phần kết hợp Text, hãy đặt thông số maxLines:

@Composable
fun LongText() {
    Text("hello ".repeat(50), maxLines = 2)
}

Một đoạn văn bản dài bị cắt ngắn sau hai dòng

Dàn chữ văn bản

Khi giới hạn một đoạn văn bản dài, bạn có thể muốn chỉ định TextOverflow. điều này chỉ xuất hiện nếu văn bản hiển thị bị cắt ngắn. Để thực hiện việc này, hãy đặt thông số textOverflow:

@Composable
fun OverflowedText() {
    Text("Hello Compose ".repeat(50), maxLines = 2, overflow = TextOverflow.Ellipsis)
}

Đoạn văn bản dài bị cắt ngắn sau ba dòng, với dấu ba chấm ở cuối

includeFontPadding and lineHeight APIs

includeFontPadding là một thuộc tính kế thừa bổ sung thêm khoảng đệm dựa trên chỉ số phông chữ ở đầu dòng đầu tiên và cuối dòng cuối cùng của văn bản. Trong phiên bản Compose 1.2.0, includeFontPadding được thiết lập thành true theo mặc định.

Bạn nên đặt includeFontPadding thành false (giúp xóa các khoảng đệm thừa) bằng cách sử dụng API thử nghiệm/không dùng nữa PlatformTextStyle trong phiên bản Compose 1.2.0 và điều chỉnh văn bản nếu cần.

@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
                )
            )
        )
    )
}

Trong các phiên bản sắp tới của Compose includeFontPadding, giá trị mặc định sẽ được đặt thành false và API PlatformTextStyle sẽ bị loại bỏ.

Hãy tham khảo bài đăng trên blog về Khắc phục khoảng đệm phông chữ trong văn bản Compose để tìm hiểu thêm về ngữ cảnh của thay đổi này, cách includeFontPadding hoạt động trong hệ thống Chế độ xem, những thay đổi mà chúng tôi đã thực hiện đối với Compose và các API LineHeightStyle mới.

Giao diện

Để sử dụng giao diện của ứng dụng cho kiểu văn bản, hãy xem tài liệu về giao diện.

Sự tương tác của người dùng

Jetpack Compose cho phép tương tác chi tiết trong Text. Hiện tại, việc lựa chọn văn bản linh hoạt hơn và có thể thực hiện trên các bố cục thành phần kết hợp. Các lượt tương tác của người dùng trong văn bản khác với các bố cục thành phần kết hợp khác, vì bạn không thể thêm công cụ sửa đổi vào một phần của thành phần kết hợp Text. Phần này làm nổi bật các API khác nhau để cho phép người dùng tương tác.

Chọn văn bản

Theo mặc định, các thành phần kết hợp không thể chọn được, nghĩa là theo mặc định, người dùng không thể chọn và sao chép văn bản từ ứng dụng của bạn. Để bật tính năng lựa chọn văn bản, bạn cần bao trùm các thành phần văn bản bằng một thành phần kết hợp SelectionContainer:

@Composable
fun SelectableText() {
    SelectionContainer {
        Text("This text is selectable")
    }
}

Một đoạn văn bản ngắn do người dùng chọn.

Bạn có thể muốn tắt tính năng lựa chọn trên các phần cụ thể của một phạm vi có thể chọn. Để làm như vậy, bạn cần bao bọc phần không được chọn bằng một thành phần kết hợp 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")
        }
    }
}

Đoạn văn bản dài hơn. Người dùng đã cố gắng chọn toàn bộ đoạn văn, nhưng vì hai dòng đã áp dụng tính năng DisableSelection nên chúng không được chọn.

Nhận vị trí của một lượt nhấp vào văn bản

Để theo dõi số lượt nhấp trên Text, bạn có thể thêm công cụ sửa đổi clickable. Tuy nhiên, nếu bạn muốn có được vị trí của một lượt nhấp trong một thành phần kết hợp Text, trong trường hợp bạn có các hành động khác nhau dựa trên các phần khác nhau của văn bản, bạn cần sử dụng một ClickableText thay thế:

@Composable
fun SimpleClickableText() {
    ClickableText(
        text = AnnotatedString("Click Me"),
        onClick = { offset ->
            Log.d("ClickableText", "$offset -th character is clicked.")
        }
    )
}

Nhấp kèm chú thích

Khi người dùng nhấp vào một thành phần kết hợp Text, bạn có thể muốn đính kèm thông tin bổ sung vào một phần của giá trị Text, ví dụ như URL được đính kèm với một từ cụ thể để mở trong trình duyệt. Để thực hiện việc này, bạn cần đính kèm chú thích, nội dung này sẽ lấy thẻ (String), một mục (String) và một phạm vi văn bản làm thông số. Từ AnnotatedString, các chú thích này có thể được lọc bằng thẻ hoặc phạm vi văn bản. Sau đây là ví dụ:

@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)
                }
        }
    )
}

Nhập và sửa đổi văn bản

TextField cho phép người dùng nhập dữ liệu và sửa đổi văn bản. Có hai cấp độ triển khai TextField:

  1. TextField là cách triển khai Material Design. Bạn nên chọn cách triển khai này vì cách này tuân theo các nguyên tắc material design:
    • Kiểu mặc định là filled
    • OutlinedTextField là phiên bản định kiểu outline
  2. BasicTextField cho phép người dùng chỉnh sửa văn bản thông qua bàn phím phần cứng hoặc phần mềm, nhưng không cung cấp đồ trang trí như gợi ý hoặc phần giữ chỗ.
@Composable
fun SimpleFilledTextFieldSample() {
    var text by remember { mutableStateOf("Hello") }

    TextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

Một trường văn bản có thể chỉnh sửa có từ "Hello". Trường này có nhãn "label" không thể chỉnh sửa.

@Composable
fun SimpleOutlinedTextFieldSample() {
    var text by remember { mutableStateOf("") }

    OutlinedTextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

Một trường văn bản có thể chỉnh sửa với đường viền và nhãn màu tím.

Tạo kiểu TextField

TextFieldBasicTextField cùng có chung nhiều thông số phổ biến để tuỳ chỉnh các thông số đó. Danh sách đầy đủ cho TextField có sẵn trong mã nguồn TextField. Đây là danh sách không đầy đủ một vài thông số hữu ích:

  • 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)
    )
}

Một TextField nhiều dòng, có hai dòng có thể chỉnh sửa cùng với nhãn

Bạn nên sử dụng TextField thay vì BasicTextField khi thiết kế yêu cầu một trường văn bản Material hoặc trường văn bản Outline. Tuy nhiên, nên sử dụng BasicTextField khi xây dựng các thiết kế không cần trang trí từ thông số Material.

Tùy chọn bàn phím

TextField cho phép bạn cài đặt các tuỳ chọn cấu hình bàn phím, chẳng hạn như bố cục bàn phím hoặc bật tính năng tự động sửa lỗi nếu được bàn phím hỗ trợ. Một số tuỳ chọn có thể không được đảm bảo nếu bàn phím phần mềm không tuân thủ các tuỳ chọn được cung cấp ở đây. Dưới đây là danh sách các tuỳ chọn bàn phím được hỗ trợ:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

Định dạng

TextField cho phép bạn cài đặt VisualTransformation trên giá trị nhập, như thay thế các ký tự bằng * cho mật khẩu, hoặc chèn dấu gạch ngang cứ sau 4 chữ số cho một số thẻ tín dụng:

@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)
    )
}

Một trường văn bản nhập mật khẩu, với văn bản bị che

Các ví dụ khác có sẵn trong mã nguồn VisualTransformSamples.

Xoá dữ liệu đầu vào

Một tác vụ phổ biến khi chỉnh sửa văn bản là xoá các ký tự ở đầu, hoặc cách khác chuyển đổi chuỗi đầu vào mỗi khi nó thay đổi.

Như một mô hình, bạn nên giả định bàn phím có thể tạo ra chỉnh sửa lớn và tuỳ ý cho từng onValueChange. Điều này có thể xảy ra, ví dụ như khi người dùng sử dụng tính năng tự động sửa, thay thế một từ bằng một biểu tượng cảm xúc hoặc các tính năng chỉnh sửa thông minh khác. Để xử lý chính xác điều này, hãy viết bất kỳ logic chuyển đổi nào với giả định rằng văn bản hiện tại đã được chuyển đến onValueChange không liên quan đến các giá trị trước đó hoặc tiếp theo sẽ được chuyển tới onValueChange.

Để triển khai trường văn bản không cho phép các số 0 ở đầu, bạn có thể thực hiện bằng cách loại bỏ tất cả các số 0 đứng đầu trên mọi thay đổi giá trị.

@Composable
fun NoLeadingZeroes() {
  var input by rememberSaveable { mutableStateOf("") }
  TextField(
      value = input,
      onValueChange = { newText ->
          input = newText.trimStart { it == '0' }
      }
  )
}

Để kiểm soát vị trí con trỏ khi xóa văn bản, hãy sử dụng phương thức nạp chồng TextFieldValue của TextField như là một phần của trạng thái.

Phông chữ có thể tải xuống

Kể từ phiên bản Compose 1.2-alpha07, bạn có thể sử dụng API phông chữ có thể tải trong ứng dụng Compose để tải Phông chữ Google xuống một cách không đồng bộ và sử dụng cho ứng dụng của bạn.

Hiện tại, chúng tôi không hỗ trợ phông chữ có thể tải xuống do tính năng này được cung cấp bởi nhà cung cấp tùy chỉnh.

Sử dụng phông chữ có thể tải xuống theo lập trình

Để tải phông chữ theo phương thức lập trình trong ứng dụng, hãy thực hiện các bước sau:

  1. Thêm phần phụ thuộc:

    Groovy

    dependencies {
        ...
        implementation "androidx.compose.ui:ui-text-google-fonts:1.2.0-beta01"
    }
    

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.2.0-beta01")
    }
  2. Khởi chạy GoogleFont.Provider bằng thông tin xác thực của Google Fonts.
    @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
    )
    
    Các tham số mà nhà cung cấp nhận được là:
    • Nhà cung cấp phông chữ cho Google Fonts.
    • Gói trình cung cấp phông chữ để xác minh danh tính của trình cung cấp
    • Danh sách tập hợp hàm băm cho các chứng chỉ để xác minh danh tính của trình cung cấp. Bạn có thể tìm các hàm băm bắt buộc cho nhà cung cấp Google Fonts ở tệp font_certs.xml trong ứng dụng mẫu JetChat.
    Lưu ý bạn cần thêm chú thích ExperimentalTextApi để có thể sử dụng các API phông chữ có thể tải xuống trong ứng dụng của mình.
  3. Xác định FontFamily như sau:
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
       Font(googleFont = GoogleFont(name), fontProvider = provider)
    )
    
    Bạn có thể truy vấn các tham số khác cho phông chữ như độ đậm và kiểu chữ bằng FontWeightFontStyle tương ứng:
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
       Font(googleFont = GoogleFont(name), fontProvider = provider,
            weight = FontWeight.Bold, style = FontStyle.Italic)
    )
    
  4. Định cấu hình FontFamily để sử dụng trong hàm kết hợp Văn bản, và thế là xong.
    Text(
        fontFamily = fontFamily,
        text = "Hello World!"
    )
    
    Bạn cũng có thể xác định Kiểu chữ để sử dụng 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
       ...
    ),
    ...
    
    Sau đó, hãy đặt Kiểu chữ thành chủ đề của ứng dụng:
    MyAppTheme(
       typography = MyTypography
    ) {
    ...
    

Để xem ví dụ về một ứng dụng triển khai phông chữ có thể tải xuống trong Compose cùng với Material3, hãy nhớ kiểm tra ứng dụng mẫu JetChat.

Phông chữ dự phòng

Bạn có thể xác định một chuỗi dự phòng cho phông chữ của mình trong trường hợp phông chữ không được tải xuống đúng cách. Chẳng hạn nếu bạn có phông chữ có thể tải xuống được xác định như sau:

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)
)

Bạn có thể xác định giá trị mặc định cho phông chữ với cả hai trọng số như sau:

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)
)

Hãy nhớ thêm chính xác dữ liệu nhập.

Việc xác định FontFamily như thế này sẽ tạo ra một FontFamily chứa hai chuỗi, mỗi trọng số một chuỗi. Cơ chế tải sẽ cố gắng phân giải phông chữ trực tuyến trước, sau đó mới đến phông chữ nằm trong thư mục tài nguyên R.font cục bộ của bạn.

Gỡ lỗi triển khai

Để xác minh liệu phông chữ có được tải xuống chính xác hay không, bạn cần xác định một trình xử lý coroutine gỡ lỗi. Trình xử lý của bạn cung cấp hành vi của việc cần làm trong trường hợp phông chữ không tải không đồng bộ được.

Hãy bắt đầu bằng cách tạo CoroutineExceptionHandler.

val handler = CoroutineExceptionHandler { _, throwable ->
   // process the Throwable
   Log.e(TAG, "There has been an issue: ", throwable)
}

Sau đó, truyền hàm này đến phương thức createFontFamilyResolver để yêu cầu trình phân giải sử dụng trình xử lý mới:

CompositionLocalProvider(
        LocalFontFamilyResolver provides createFontFamilyResolver(LocalContext.current, handler)
    ) {
        Column {
            Text(
                text = "Hello World!",
                style = MaterialTheme.typography.body1
            )
        }
    }

Bạn cũng có thể sử dụng API isAvailableOnDevice của nhà cung cấp để kiểm tra xem họ có sẵn không và các chứng chỉ có được định cấu hình chính xác hay không. Để thực hiện việc này, bạn có thể gọi phương thức isAvailableOnDevice trả về giá trị false nếu nhà cung cấp được định cấu hình không chính xác.

val context = LocalContext.current
LaunchedEffect(Unit) {
   if (provider.isAvailableOnDevice(context)) {
       Log.d(TAG, "Success!")
   }
}

Chú ý

Google Fonts mất vài tháng để cung cấp phông chữ mới trên Android. Có một khoảng thời gian trống giữa thời điểm phông chữ được thêm vào fonts.google.com và thời điểm phông chữ đó có sẵn thông qua API phông chữ có thể tải xuống (trong hệ thống chế độ xem hoặc trong Compose). Phông chữ mới được thêm vào có thể không tải được trên ứng dụng của bạn bằng IllegalStateException. Để giúp nhà phát triển xác định lỗi này so với các loại lỗi tải phông chữ khác, chúng tôi đã thêm thông báo mô tả cho trường hợp ngoại lệ này trong Compose với những thay đổi tại đây.