Thao tác với phông chữ

Trang này mô tả cách đặt phông chữ trong ứng dụng Compose.

Đặt 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)
    }
}

Các từ

Bạn có thể 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 được 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 sẽ 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)
)

Bạn có thể truyền fontFamily này đến thành phần kết hợp Text. Vì fontFamily có thể bao gồm nhiều trọng số, nên bạn có thể thiết lập 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(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
    Text(
        text = "text",
        fontFamily = firaSansFamily,
        fontWeight = FontWeight.Normal,
        fontStyle = FontStyle.Italic
    )
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}

Các từ

Để tìm hiểu cách thiết lập kiểu chữ trong toàn bộ ứng dụng, hãy xem bài viết Hệ thống thiết kế tuỳ chỉnh trong Compose.

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

Kể từ Compose 1.2.0, bạn có thể sử dụng API phông chữ có thể tải xuống trong ứng dụng Compose để tải phông chữ của Google xuống một cách không đồng bộ và sử dụng chúng trong ứ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 nhà cung cấp tuỳ chỉnh cung cấp.

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

Để tải phông chữ theo phương thức lập trình xuống từ ứng dụng, hãy làm theo các bước sau:

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

    Groovy

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

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.6.8")
    }
  2. Khởi động GoogleFont.Provider bằng thông tin xác thực của Google 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
    )
    Các thông số mà trì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 thấy các hàm băm bắt buộc cho trình cung cấp Google Fonts ở tệp font_certs.xml trong ứng dụng mẫu Jetchat.
  3. Xác định 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)
    )
    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 lần lượt:
    // ...
     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
        )
    )
  4. Định cấu hình FontFamily để dùng trong hàm có khả năng kết hợp Văn bản:

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(
    labelMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp/*...*/
    ),
    labelLarge = TextStyle(
        fontFamily = fontFamily,
        fontWeight = FontWeight.Bold,
        letterSpacing = 2.sp,
        /*...*/
    ),
    displayMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.SemiBold/*...*/
    ),
    /*...*/
)

Tiếp theo, hãy đặt Kiểu chữ thành giao diện của ứng dụng:

MyAppTheme(
    typography = MyTypography
)/*...*/

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

Thêm 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 như 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 trước tiên sẽ cố gắng phân giải phông chữ trực tuyến, sau đó là phông chữ nằm trong thư mục tài nguyên R.font cục bộ.

Gỡ lỗi triển khai của bạn

Để 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 một CoroutineExceptionHandler:

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

Chuyển hàm đó đế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.bodyMedium
        )
    }
}

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 trống về thời gian 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 Khung hiển thị hoặc trong Compose). Các phông chữ mới thêm có thể không tải được trong ứng dụng của bạn có 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 cùng với những thay đổi tại đây. Nếu bạn phát hiện thấy vấn đề, hãy báo cáo vấn đề đó bằng cách sử dụng công cụ theo dõi lỗi.

Sử dụng phông chữ có thể thay đổi

Phông chữ biến là một định dạng phông chữ cho phép một tệp phông chữ chứa nhiều kiểu. Với phông chữ có thể thay đổi, bạn có thể sửa đổi các trục (hoặc tham số) để tạo kiểu mà mình muốn. Các trục này có thể là trục chuẩn, chẳng hạn như độ đậm, chiều rộng, độ xiên và kiểu nghiêng hoặc trục tuỳ chỉnh (khác nhau trên các phông chữ thay đổi).

5 cấu hình của cùng một phông chữ có thể thay đổi với các giá trị trục khác nhau.
Hình 1. Văn bản dùng cùng một phông chữ biến được tuỳ chỉnh với các giá trị trục khác nhau.

Việc sử dụng phông chữ biến thay vì các tệp phông chữ thông thường cho phép bạn chỉ có một tệp phông chữ thay vì nhiều tệp.

Để biết thêm thông tin cơ bản về các phông chữ biến đổi, hãy xem bài viết Kiến thức về Google Fonts, toàn bộ danh mục các phông chữ biến thể có sẵn và bảng các trục được hỗ trợ cho mỗi phông chữ.

Tài liệu này hướng dẫn bạn cách triển khai một phông chữ có thể thay đổi trong ứng dụng Compose.

Tải phông chữ có thể thay đổi

  1. Tải phông chữ biến mà bạn muốn sử dụng xuống (ví dụ: Roboto Flex) rồi đặt phông chữ đó vào thư mục app/res/font trong ứng dụng của bạn. Hãy đảm bảo rằng tệp .Tệp ttf mà bạn thêm là phiên bản phông chữ biến của phông chữ, và tên của tệp phông chữ đều là chữ thường và không chứa bất kỳ ký tự đặc biệt nào.

  2. Để tải phông chữ có thể thay đổi, hãy xác định FontFamily bằng cách sử dụng phông chữ đặt trong thư mục res/font/:

    // In Typography.kt
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily =
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )

    API FontVariation cho phép bạn định cấu hình các trục phông chữ chuẩn như độ đậm, chiều rộngđộ nghiêng. Đây là các trục chuẩn có sẵn với bất kỳ phông chữ biến đổi nào. Bạn có thể tạo nhiều cấu hình phông chữ tuỳ vào vị trí phông chữ sẽ được sử dụng.

  3. Phông chữ biến chỉ có sẵn cho Android phiên bản O trở lên. Vì vậy, hãy thêm một lan can và định cấu hình một biện pháp dự phòng thích hợp:

    // In Typography.kt
    val default = FontFamily(
        /*
        * This can be any font that makes sense
        */
        Font(
            R.font.robotoflex_static_regular
        )
    )
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )
    } else {
        default
    }

  4. Trích xuất các chế độ cài đặt thành một tập hợp các hằng số để sử dụng lại dễ dàng hơn và thay thế các chế độ cài đặt phông chữ bằng những hằng số sau:

    // VariableFontDimension.kt
    object DisplayLargeVFConfig {
        const val WEIGHT = 950
        const val WIDTH = 30f
        const val SLANT = -6f
        const val ASCENDER_HEIGHT = 800f
        const val COUNTER_WIDTH = 500
    }
    
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                )
            )
        )
    } else {
        default
    }

  5. Định cấu hình kiểu chữ Material Design 3 để sử dụng FontFamily:

    // Type.kt
    val Typography = Typography(
        displayLarge = TextStyle(
            fontFamily = displayLargeFontFamily,
            fontSize = 50.sp,
            lineHeight = 64.sp,
            letterSpacing = 0.sp,
            /***/
        )
    )

    Mẫu này sử dụng kiểu chữ trong Material 3 displayLarge, có các chế độ cài đặt phông chữ mặc định khác và các trường hợp sử dụng được đề xuất. Ví dụ: bạn nên sử dụng displayLarge cho văn bản ngắn, quan trọng, vì đây là văn bản lớn nhất trên màn hình.

    Với Material 3, bạn có thể thay đổi các giá trị mặc định của TextStylefontFamily để tuỳ chỉnh kiểu chữ. Trong đoạn mã trên, bạn định cấu hình các phiên bản của TextStyle để tuỳ chỉnh chế độ cài đặt phông chữ cho từng bộ phông chữ.

  6. Bây giờ, bạn đã xác định được kiểu chữ, hãy truyền kiểu chữ đó vào MaterialTheme của M3:

    MaterialTheme(
        colorScheme = MaterialTheme.colorScheme,
        typography = Typography,
        content = content
    )

  7. Cuối cùng, hãy sử dụng thành phần kết hợp Text và chỉ định kiểu cho một trong các kiểu chữ đã xác định, MaterialTheme.typography.displayLarge:

    @Composable
    @Preview
    fun CardDetails() {
        MyCustomTheme {
            Card(
                shape = RoundedCornerShape(8.dp),
                elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            ) {
                Column(
                    modifier = Modifier.padding(16.dp)
                ) {
                    Text(
                        text = "Compose",
                        style = MaterialTheme.typography.displayLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 1
                    )
                    Text(
                        text = "Beautiful UIs on Android",
                        style = MaterialTheme.typography.headlineMedium,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 2
                    )
                    Text(
                        text = "Jetpack Compose is Android’s recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.",
                        style = MaterialTheme.typography.bodyLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 3
                    )
                }
            }
        }
    }

    Mỗi thành phần kết hợp Text được định cấu hình thông qua kiểu của giao diện Material và chứa một cấu hình phông chữ đa dạng. Bạn có thể sử dụng MaterialTheme.typography để truy xuất kiểu chữ được cung cấp cho thành phần kết hợp MaterialTheme của M3.

3 văn bản khác nhau, tất cả đều thể hiện các cấu hình phông chữ khác nhau.
Hình 2. Phông chữ có thể thay đổi được áp dụng trong 3 cấu hình.

Sử dụng trục tuỳ chỉnh

Phông chữ cũng có thể có các trục tuỳ chỉnh. Các thuộc tính này được xác định trong chính tệp phông chữ. Ví dụ: phông chữ Roboto Flex có trục chiều cao tăng dần ("YTAS"), giúp điều chỉnh chiều cao của phần chữ thường, trong khi chiều rộng của bộ đếm ("XTRA") điều chỉnh chiều rộng của từng chữ cái.

Bạn có thể thay đổi giá trị của các trục này bằng chế độ cài đặt FontVariation.

Để biết thêm thông tin về các trục tuỳ chỉnh mà bạn có thể định cấu hình cho một phông chữ, hãy xem bảng các trục được hỗ trợ cho từng phông chữ.

  1. Để sử dụng trục tuỳ chỉnh, hãy xác định hàm cho trục ascenderHeightcounterWidth tuỳ chỉnh:

    fun ascenderHeight(ascenderHeight: Float): FontVariation.Setting {
        require(ascenderHeight in 649f..854f) { "'Ascender Height' must be in 649f..854f" }
        return FontVariation.Setting("YTAS", ascenderHeight)
    }
    
    fun counterWidth(counterWidth: Int): FontVariation.Setting {
        require(counterWidth in 323..603) { "'Counter width' must be in 323..603" }
        return FontVariation.Setting("XTRA", counterWidth.toFloat())
    }

    Các hàm này thực hiện những việc sau:

    • Xác định các biện pháp bảo vệ cho các giá trị mà các em có thể chấp nhận. Như bạn có thể thấy trong Danh mục phông chữ biến, ascenderHeight (YTAS) có giá trị tối thiểu là 649f và tối đa là 854f.
    • Trả về chế độ cài đặt phông chữ để cấu hình sẵn sàng thêm vào phông chữ. Trong phương thức FontVariation.Setting(), tên trục (YTAS, XTRA) được mã hoá cứng và lấy giá trị làm tham số.
  2. Khi sử dụng các trục có cấu hình phông chữ, hãy truyền các tham số bổ sung vào từng Font được tải:

    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                    ascenderHeight(DisplayLargeVFConfig.ASCENDER_HEIGHT),
                    counterWidth(DisplayLargeVFConfig.COUNTER_WIDTH)
                )
            )
        )
    } else {
        default
    }

    Lưu ý rằng chiều cao của phần đuôi viết thường hiện đã tăng lên và văn bản khác thì rộng hơn:

Ba văn bản khác nhau cho thấy các cấu hình khác nhau cho các phông chữ biến đổi, với các trục tuỳ chỉnh được thiết lập – một số có phần chữ thường cao hơn và rộng hơn trước.
Hình 3. Văn bản cho thấy các trục tuỳ chỉnh được đặt trên phông chữ có thể thay đổi.

Tài nguyên khác

Để biết thêm thông tin, hãy xem bài đăng trên blog sau đây về phông chữ thay đổi: