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

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

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

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

@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

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

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

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

ใช้แบบอักษรที่ดาวน์โหลดได้โดยอัตโนมัติ

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

  1. เพิ่มการอ้างอิงด้วยคำสั่งต่อไปนี้

    Groovy

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

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.8.1")
    }
  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)
)

คุณกำหนดค่าเริ่มต้นสำหรับแบบอักษรสำหรับทั้ง 2 น้ำหนักได้ดังนี้

// ...
 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 เส้นต่อ 1 น้ำหนัก กลไกการโหลดจะพยายามใช้แบบอักษรที่ออนไลน์ก่อน จากนั้นจึงใช้แบบอักษรที่อยู่ในโฟลเดอร์ทรัพยากร R.font ในเครื่อง

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

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

เริ่มต้นด้วยการสร้าง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 แบบอักษรที่ดาวน์โหลดได้ (ไม่ว่าจะใน View system หรือใน Compose) แบบอักษรที่เพิ่งเพิ่ม อาจโหลดในแอปไม่สำเร็จพร้อมกับ IllegalStateException เราได้เพิ่มข้อความอธิบายสำหรับข้อยกเว้นใน Compose พร้อมการเปลี่ยนแปลง ที่นี่ เพื่อช่วยให้นักพัฒนาแอประบุข้อผิดพลาดนี้จากข้อผิดพลาดในการโหลดแบบอักษรประเภทอื่นๆ หากพบปัญหา โปรดรายงานโดยใช้เครื่องมือติดตามปัญหา

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

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

การกำหนดค่า 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 ช่วยให้คุณกำหนดค่าแกนแบบอักษรมาตรฐาน เช่น weight, width และ slant ได้ แกนเหล่านี้เป็นแกนมาตรฐานที่ ใช้ได้กับแบบอักษรตัวแปร คุณสร้างการกำหนดค่าที่แตกต่างกันของ แบบอักษรได้โดยอิงตามตำแหน่งที่จะใช้แบบอักษร

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

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

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

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