با فونت کار کنید

این صفحه نحوه تنظیم فونت‌ها در برنامه 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 composable خود منتقل کنید. از آنجا که یک 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 مراجعه کنید.

فونت‌های قابل دانلود

از نسخه ۱.۲.۰ به بعد، می‌توانید از API فونت‌های قابل دانلود در برنامه Compose خود برای دانلود فونت‌های گوگل به صورت غیرهمزمان و استفاده از آنها در برنامه خود استفاده کنید.

پشتیبانی از فونت‌های قابل دانلود ارائه شده توسط ارائه دهندگان سفارشی در حال حاضر در دسترس نیست.

استفاده از فونت‌های قابل دانلود به صورت برنامه‌نویسی شده

برای دانلود فونت از طریق برنامه‌نویسی از داخل برنامه، این مراحل را دنبال کنید:

  1. وابستگی را اضافه کنید:

    گرووی

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

    کاتلین

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.9.3")
    }
  2. مقداردهی اولیه GoogleFont.Provider با اعتبارنامه‌های فونت‌های گوگل:
    val provider = GoogleFont.Provider(
        providerAuthority = "com.google.android.gms.fonts",
        providerPackage = "com.google.android.gms",
        certificates = R.array.com_google_android_gms_fonts_certs
    )
    پارامترهایی که ارائه دهنده دریافت می‌کند عبارتند از:
    • مرجع ارائه دهنده فونت برای فونت‌های گوگل.
    • بسته ارائه دهنده فونت برای تأیید هویت ارائه دهنده.
    • فهرستی از مجموعه هش‌ها برای گواهی‌ها جهت تأیید هویت ارائه‌دهنده. می‌توانید هش‌های مورد نیاز برای ارائه‌دهنده فونت‌های گوگل را در فایل 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!"
)

همچنین می‌توانید Typography را برای استفاده از 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/*...*/
    ),
    /*...*/
)

سپس، Typography را روی تم برنامه خود تنظیم کنید:

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 شامل دو زنجیره، یکی به ازای هر وزن، ایجاد می‌کند. مکانیزم بارگذاری ابتدا سعی می‌کند فونت آنلاین و سپس فونت واقع در پوشه منبع محلی R.font شما را شناسایی کند.

پیاده‌سازی خود را اشکال‌زدایی کنید

برای کمک به شما در تأیید اینکه آیا فونت به درستی دانلود می‌شود، می‌توانید یک کنترل‌کننده‌ی کوروتین اشکال‌زدایی تعریف کنید. کنترل‌کننده‌ی شما رفتاری را ارائه می‌دهد که در صورت عدم موفقیت فونت در بارگیری ناهمگام، چه کاری باید انجام شود.

با ایجاد یک CoroutineExceptionHandler شروع کنید:

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

آن را به متد createFontFamilyResolver ارسال کنید تا resolver از هندلر جدید استفاده کند:

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

همچنین می‌توانید از API isAvailableOnDevice از ارائه‌دهنده برای بررسی در دسترس بودن ارائه‌دهنده و پیکربندی صحیح گواهی‌ها استفاده کنید. برای انجام این کار، می‌توانید متد isAvailableOnDevice را فراخوانی کنید که در صورت پیکربندی نادرست ارائه‌دهنده، مقدار false را برمی‌گرداند.

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

هشدارها

چندین ماه طول می‌کشد تا فونت‌های جدید گوگل فونتز در اندروید در دسترس قرار گیرند. بین زمانی که یک فونت در fonts.google.com اضافه می‌شود و زمانی که از طریق API فونت‌های قابل دانلود (چه در سیستم View و چه در Compose) در دسترس قرار می‌گیرد، فاصله زمانی وجود دارد. فونت‌های تازه اضافه شده ممکن است در برنامه شما با خطای IllegalStateException بارگذاری نشوند. برای کمک به توسعه‌دهندگان در شناسایی این خطا نسبت به سایر انواع خطاهای بارگذاری فونت، ما پیام‌های توصیفی را برای استثنا در Compose با تغییرات اینجا اضافه کرده‌ایم. در صورت مشاهده هرگونه مشکل، آنها را با استفاده از ردیاب مشکل گزارش دهید.

استفاده از فونت‌های متغیر

فونت متغیر، فرمتی از فونت است که به یک فایل فونت اجازه می‌دهد سبک‌های مختلفی را در خود جای دهد. با فونت‌های متغیر، می‌توانید محورها (یا پارامترها) را برای ایجاد سبک دلخواه خود تغییر دهید. این محورها می‌توانند استاندارد باشند، مانند وزن، عرض، شیب و ایتالیک، یا سفارشی باشند، که در فونت‌های متغیر متفاوت است.

پنج پیکربندی از یک فونت متغیر یکسان با مقادیر محور متفاوت.
شکل ۱. متن با استفاده از فونت متغیر یکسان که با مقادیر مختلف محور سفارشی‌سازی شده است.

استفاده از فونت‌های متغیر به جای فایل‌های فونت معمولی به شما این امکان را می‌دهد که به جای چندین فایل فونت، فقط یک فایل فونت داشته باشید.

برای اطلاعات بیشتر در مورد فونت‌های متغیر، به بخش «دانش فونت‌های گوگل» ، فهرست کامل فونت‌های متغیر موجود و جدولی از محورهای پشتیبانی شده برای هر فونت مراجعه کنید.

این سند به شما نشان می‌دهد که چگونه یک فونت متغیر را در برنامه 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),
                )
            )
        )

    API FontVariation به شما امکان می‌دهد محورهای استاندارد فونت مانند weight ، width و slant را پیکربندی کنید. این‌ها محورهای استانداردی هستند که با هر فونت متغیری در دسترس هستند. می‌توانید پیکربندی‌های مختلفی از فونت را بر اساس محل استفاده آن ایجاد کنید.

  3. فونت‌های متغیر فقط برای نسخه‌های اندروید 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 برای متن کوتاه و مهم استفاده کنید، زیرا بزرگترین متن روی صفحه است.

    با متریال ۳، می‌توانید مقادیر پیش‌فرض TextStyle و fontFamily را برای سفارشی‌سازی تایپوگرافی خود تغییر دهید. در قطعه کد بالا، نمونه‌هایی از TextStyle برای سفارشی‌سازی تنظیمات فونت برای هر خانواده فونت پیکربندی می‌کنید.

  6. حالا که تایپوگرافی خود را تعریف کرده‌اید، آن را به M3 MaterialTheme ارسال کنید:

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

  7. در نهایت، از یک Text composable استفاده کنید و استایل را به یکی از استایل‌های تایپوگرافی تعریف‌شده، 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 از طریق سبک تم متریال خود پیکربندی می‌شود و شامل پیکربندی فونت متغیر متفاوتی است. می‌توانید از MaterialTheme.typography برای بازیابی تایپوگرافی ارائه شده به ترکیب‌بندی M3 MaterialTheme استفاده کنید.

سه متن مختلف، که هر سه پیکربندی فونت متفاوتی را نشان می‌دهند.
شکل ۲. فونت متغیر اعمال شده در سه پیکربندی مختلف.

استفاده از محورهای سفارشی

فونت‌ها همچنین می‌توانند محورهای سفارشی داشته باشند. این محورها در خود فایل فونت تعریف می‌شوند. برای مثال، فونت 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
    }

    توجه کنید که ارتفاع حروف کوچک افزایش یافته و متن دیگر پهن‌تر شده است:

سه متن مختلف که پیکربندی‌های متفاوتی را برای فونت‌های متغیر نشان می‌دهند، با محورهای سفارشی تنظیم شده - برخی دارای حروف کوچک صعودی بالاتر و عریض‌تر از قبل هستند.
شکل ۳. متنی که محورهای سفارشی تنظیم‌شده روی فونت‌های متغیر را نشان می‌دهد.

منابع اضافی

برای اطلاعات بیشتر، به پست وبلاگ زیر در مورد فونت‌های متغیر مراجعه کنید:

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}