การทำงานกับแบบอักษร

หน้านี้จะอธิบายวิธีตั้งค่าแบบอักษรในแอปเขียน

ตั้งค่าแบบอักษร

Textมีพารามิเตอร์ fontFamily ที่ให้ตั้งค่าแบบอักษรที่ใช้ในคอมโพสิเบิล โดยค่าเริ่มต้น ระบบจะรวมชุดแบบอักษร Serif, Sans-Serif, Monospace และแบบตัวเขียนไว้ให้

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

คํา

คุณสามารถใช้แอตทริบิวต์ fontFamily เพื่อทำงานกับแบบอักษรและแบบตัวพิมพ์ที่กำหนดเองซึ่งกำหนดไว้ในโฟลเดอร์ res/font ดังนี้

ภาพกราฟิกของโฟลเดอร์ res > font ในสภาพแวดล้อมการพัฒนา

ตัวอย่างนี้แสดงวิธีกำหนด fontFamily ตามไฟล์แบบอักษรเหล่านั้น และใช้ฟังก์ชัน 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)
)

คุณสามารถส่ง fontFamily นี้ไปยังคอมโพสิเบิล Text ได้ เนื่องจาก fontFamily สามารถมีน้ำหนักที่แตกต่างกัน คุณจึงตั้งค่า fontWeight ด้วยตนเองเพื่อเลือกน้ำหนักที่เหมาะสมสำหรับข้อความได้ ดังนี้

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

คํา

ดูวิธีตั้งค่าแบบอักษรในแอปทั้งหมดได้ที่ระบบการออกแบบที่กำหนดเองในเครื่องมือเขียน

แบบอักษรที่ดาวน์โหลดได้

ตั้งแต่ Compose 1.2.0 เป็นต้นไป คุณจะใช้ API แบบดาวน์โหลดได้ในแอป Compose เพื่อดาวน์โหลดแบบอักษรของ Google แบบไม่พร้อมกันและใช้แบบอักษรดังกล่าวในแอปได้

ขณะนี้ระบบยังไม่รองรับแบบอักษรที่ดาวน์โหลดได้ซึ่งให้บริการโดยผู้ให้บริการที่กำหนดเอง

ใช้แบบอักษรที่ดาวน์โหลดได้แบบเป็นโปรแกรม

หากต้องการดาวน์โหลดแบบอักษรแบบเป็นโปรแกรมจากภายในแอป ให้ทำตามขั้นตอนต่อไปนี้

  1. เพิ่มการพึ่งพา ดังนี้

    Groovy

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

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.7.5")
    }
  2. เริ่มต้นตัวแปร GoogleFont.Provider ด้วยข้อมูลเข้าสู่ระบบสำหรับ 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
    )
    พารามิเตอร์ที่ผู้ให้บริการได้รับมีดังนี้
    • หน่วยงานที่ดูแลผู้ให้บริการแบบอักษรสำหรับ Google Fonts
    • แพ็กเกจผู้ให้บริการแบบอักษรเพื่อยืนยันตัวตนของผู้ให้บริการ
    • รายการชุดแฮชสําหรับใบรับรองเพื่อยืนยันตัวตนของผู้ให้บริการ คุณดูแฮชที่จําเป็นสําหรับผู้ให้บริการ Google Fonts ได้ในไฟล์ font_certs.xml ในแอปตัวอย่าง Jetchat
  3. กำหนด 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
        )
    )
  4. กำหนดค่า FontFamily เพื่อใช้ในฟังก์ชันคอมโพสิเบิลข้อความ

Text(
    fontFamily = fontFamily, text = "Hello World!"
)

นอกจากนี้ คุณยังกำหนดการจัดรูปแบบข้อความเพื่อใช้ FontFamily ได้ด้วย โดยทำดังนี้

val MyTypography = Typography(
    bodyMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp/*...*/
    ),
    bodyLarge = TextStyle(
        fontFamily = fontFamily,
        fontWeight = FontWeight.Bold,
        letterSpacing = 2.sp,
        /*...*/
    ),
    headlineMedium = 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 ที่มีเชน 2 เส้น เชนละ 1 เส้นตามน้ำหนัก กลไกการโหลดจะพยายามแก้ไขแบบอักษรออนไลน์ก่อน จากนั้นจึงแก้ไขแบบอักษรที่อยู่ในโฟลเดอร์ทรัพยากร R.font บนเครื่อง

แก้ไขข้อบกพร่องในการติดตั้งใช้งาน

คุณสามารถกําหนดตัวแฮนเดิล coroutine ที่ใช้แก้ไขข้อบกพร่องเพื่อช่วยตรวจสอบว่าระบบดาวน์โหลดแบบอักษรอย่างถูกต้องหรือไม่ แฮนเดิลจะระบุลักษณะการทําในกรณีที่แบบอักษรโหลดแบบไม่พร้อมกันไม่สําเร็จ

เริ่มต้นด้วยการสร้าง 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.bodyMedium
        )
    }
}

นอกจากนี้ คุณยังใช้ API จากผู้ให้บริการเพื่อทดสอบว่าผู้ให้บริการพร้อมให้บริการและใบรับรองได้รับการกําหนดค่าอย่างถูกต้องหรือไม่ได้ด้วย isAvailableOnDevice โดยสามารถเรียกใช้เมธอด isAvailableOnDevice ที่แสดงผลเป็นเท็จหากกําหนดค่าผู้ให้บริการไม่ถูกต้อง

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

ข้อจำกัด

Google Fonts ใช้เวลาหลายเดือนในการทำให้แบบอักษรใหม่พร้อมใช้งานใน Android ช่วงเวลาระหว่างที่มีการเพิ่มแบบอักษรใน fonts.google.com กับเวลาที่แบบอักษรพร้อมใช้งานผ่าน API แบบอักษรที่ดาวน์โหลดได้ (ในระบบมุมมองหรือในเครื่องมือเขียน) จะแตกต่างกันไป แบบอักษรที่เพิ่มใหม่อาจโหลดในแอปด้วย IllegalStateException ไม่สำเร็จ เพื่อช่วยนักพัฒนาแอปในการระบุข้อผิดพลาดนี้จากข้อผิดพลาดในการโหลดแบบอักษรประเภทอื่นๆ เราจึงได้เพิ่มข้อความที่อธิบายข้อยกเว้นในเครื่องมือเขียนพร้อมกับการเปลี่ยนแปลงนี้ ที่นี่ หากพบปัญหา โปรดรายงานโดยใช้เครื่องมือติดตามปัญหา

ใช้แบบอักษรที่ปรับแต่งได้

แบบอักษรที่ปรับแต่งได้คือรูปแบบแบบอักษรที่อนุญาตให้ไฟล์แบบอักษรไฟล์หนึ่งมีสไตล์ที่แตกต่างกัน เมื่อใช้แบบอักษรแบบแปรผัน คุณจะแก้ไขแกน (หรือพารามิเตอร์) เพื่อสร้างสไตล์ที่ต้องการได้ ซึ่งอาจเป็นค่ามาตรฐาน เช่น ความหนา ความกว้าง ความเอียง และตัวเอียง หรือค่าที่กำหนดเอง ซึ่งจะแตกต่างกันไปตามแบบอักษรแบบแปรผัน

การกําหนดค่าแบบต่างๆ 5 รายการของแบบอักษรแบบแปรผันเดียวกันซึ่งมีค่าแกนต่างกัน
รูปที่ 1 ข้อความที่ใช้แบบอักษรแบบผันแปรเดียวกันซึ่งปรับแต่งด้วยค่าแกนที่แตกต่างกัน

การใช้แบบอักษรแบบแปรผันแทนไฟล์แบบอักษรปกติจะช่วยให้คุณมีไฟล์แบบอักษรเพียงไฟล์เดียวแทนที่จะเป็นหลายไฟล์

ดูข้อมูลเบื้องต้นเพิ่มเติมเกี่ยวกับแบบอักษรที่เปลี่ยนแปลงได้ได้ที่ความรู้เกี่ยวกับ Google Fonts, แคตตาล็อกทั้งหมดของแบบอักษรที่เปลี่ยนแปลงได้ที่มี และตารางแกนแนวตั้งและแนวนอนที่รองรับสำหรับแบบอักษรแต่ละแบบ

เอกสารนี้จะแสดงวิธีใช้แบบอักษรแบบผันแปรในแอป Compose

โหลดแบบอักษรที่ปรับแต่งได้

  1. ดาวน์โหลดแบบอักษรแบบผันแปรที่ต้องการใช้ (เช่น Roboto Flex) แล้ววางไว้ในโฟลเดอร์ app/res/font ในแอป ตรวจสอบว่าttf ไฟล์ที่คุณเพิ่มเป็นแบบอักษรเวอร์ชันแบบปรับเปลี่ยนได้ของแบบอักษร และชื่อไฟล์แบบอักษรเป็นอักษรตัวพิมพ์เล็กทั้งหมดและไม่มีอักขระพิเศษ

  2. หากต้องการโหลดแบบอักษรแบบแปรผัน ให้กําหนด FontFamily โดยใช้แบบอักษรที่อยู่ในไดเรกทอรี 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),
                )
            )
        )

    FontVariation API ช่วยให้คุณกำหนดค่าแกนตัวอักษรมาตรฐานได้ เช่น น้ำหนัก ความกว้าง และความเอียง แกนเหล่านี้เป็นแกนมาตรฐานที่ใช้ได้กับแบบอักษรแบบผันแปรใดก็ได้ คุณสร้างการกำหนดค่าแบบต่างๆ ของแบบอักษรได้ตามตำแหน่งที่จะใช้แบบอักษร

  3. แบบอักษรแบบแปรผันใช้ได้กับ Android เวอร์ชัน O ขึ้นไปเท่านั้น ดังนั้นให้เพิ่มการกํากับดูแลและกำหนดค่าแบบอักษรสำรองที่เหมาะสม ดังนี้

    // 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. ดึงข้อมูลการตั้งค่าออกเป็นชุดค่าคงที่เพื่อให้นํามาใช้ซ้ำได้ง่ายขึ้น และแทนที่การตั้งค่าแบบอักษรด้วยค่าคงที่เหล่านี้

    // 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. กำหนดค่าแบบอักษร Material Design 3 เพื่อใช้ FontFamily

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

    ตัวอย่างนี้ใช้ displayLarge แบบอักษร Material 3 ซึ่งมีการตั้งค่าแบบอักษรเริ่มต้นและการใช้งานที่แนะนำที่แตกต่างกัน เช่น คุณควรใช้ displayLarge สำหรับข้อความสั้นๆ ที่สำคัญ เนื่องจากเป็นข้อความที่ใหญ่ที่สุดบนหน้าจอ

    เมื่อใช้ Material 3 คุณจะเปลี่ยนค่าเริ่มต้นของ TextStyle และ fontFamily เพื่อปรับแต่งแบบอักษรได้ ในสนิปเก็ตด้านบน คุณจะกําหนดค่าอินสแตนซ์ของ TextStyle เพื่อปรับแต่งการตั้งค่าแบบอักษรสําหรับชุดแบบอักษรแต่ละชุด

  6. เมื่อกําหนดแบบอักษรแล้ว ให้ส่งไปยัง M3 MaterialTheme ดังนี้

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

  7. สุดท้าย ให้ใช้คอมโพสิเบิล Text และระบุรูปแบบเป็นรูปแบบตัวอักษร 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
                    )
                }
            }
        }
    }

    คอมโพสิเบิล Text แต่ละรายการได้รับการกําหนดค่าผ่านสไตล์ของธีม Material และมีการกําหนดค่าแบบอักษรแบบปรับเปลี่ยนได้ที่แตกต่างกัน คุณสามารถใช้ MaterialTheme.typography เพื่อเรียกข้อมูลแบบอักษรที่ระบุให้กับ Composable M3 MaterialTheme

ข้อความ 3 ข้อความที่แสดงการกำหนดค่าแบบอักษรที่แตกต่างกัน
รูปที่ 2 แบบอักษรแบบผันที่ใช้ในการกําหนดค่า 3 แบบ

ใช้แกนที่กำหนดเอง

นอกจากนี้ แบบอักษรยังมีแกนที่กำหนดเองได้อีกด้วย ซึ่งจะกำหนดไว้ในไฟล์แบบอักษรเอง เช่น แบบอักษร Roboto Flex มีแกนความสูงของส่วนยื่นขึ้น ("YTAS") ซึ่งจะปรับความสูงของส่วนยื่นขึ้นของตัวพิมพ์เล็ก ส่วนความกว้างของส่วนยื่นลง ("XTRA") จะปรับความกว้างของแต่ละตัวอักษร

คุณเปลี่ยนค่าของแกนเหล่านี้ได้โดยใช้การตั้งค่า FontVariation

ดูข้อมูลเพิ่มเติมเกี่ยวกับแกนที่กำหนดเองซึ่งคุณกำหนดค่าสำหรับแบบอักษรได้ได้ที่ตารางแกนที่รองรับสำหรับแบบอักษรแต่ละแบบ

  1. หากต้องการใช้แกนที่กำหนดเอง ให้กำหนดฟังก์ชันสำหรับแกน ascenderHeight และ counterWidth ที่กําหนดเอง ดังนี้

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

    ฟังก์ชันเหล่านี้ทําสิ่งต่อไปนี้

    • กําหนดขอบเขตของค่าที่ยอมรับได้ ดังที่คุณเห็นในแคตตาล็อกแบบอักษรแบบแปรผัน ascenderHeight (YTAS) มีค่าต่ำสุด 649f และค่าสูงสุด 854f
    • กลับไปที่การตั้งค่าแบบอักษรเพื่อให้การกำหนดค่าพร้อมที่จะเพิ่มลงในแบบอักษร ในเมธอด FontVariation.Setting() ชื่อแกน (YTAS, XTRA) ได้รับการกําหนดไว้ล่วงหน้า และจะรับค่าเป็นพารามิเตอร์
  2. เมื่อใช้แกนกับการกำหนดค่าแบบอักษร ให้ส่งพารามิเตอร์เพิ่มเติมไปยัง Font แต่ละรายการที่โหลด

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

    โปรดสังเกตว่าตอนนี้ความสูงของส่วนเกินเส้นบรรทัดบนของตัวอักษรพิมพ์เล็กเพิ่มขึ้น และข้อความอื่นๆ กว้างขึ้น

ข้อความ 3 รายการที่แสดงการกำหนดค่าที่แตกต่างกันสำหรับแบบอักษรแบบแปรผัน โดยมีการตั้งค่าแกนที่กำหนดเอง ซึ่งบางรายการมีอักษรตัวพิมพ์เล็กที่สูงและกว้างกว่าก่อนหน้านี้
รูปที่ 3 ข้อความแสดงแกนที่กำหนดเองซึ่งตั้งค่าไว้ในแบบอักษรแบบผันแปร

แหล่งข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมได้ที่บล็อกโพสต์ต่อไปนี้เกี่ยวกับแบบอักษรแบบแปรผัน