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

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

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

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 ข้อความแสดงแกนที่กำหนดเองซึ่งมีแบบอักษรที่เปลี่ยนแปลงได้

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

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