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

در این صفحه نحوه تنظیم فونت در برنامه Compose توضیح داده شده است.

تنظیم فونت

Text دارای یک پارامتر fontFamily است تا امکان تنظیم فونت مورد استفاده در composable را فراهم کند. به طور پیش‌فرض، خانواده‌های فونت سریف، 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 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 مراجعه کنید.

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

با شروع در Compose 1.2.0 ، می‌توانید از API فونت‌های قابل دانلود در برنامه Compose خود برای دانلود فونت‌های Google به صورت ناهمزمان و استفاده از آنها در برنامه خود استفاده کنید.

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

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

برای دانلود یک فونت به صورت برنامه‌ریزی شده از داخل برنامه، مراحل زیر را دنبال کنید:

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

    شیار

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

    کاتلین

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.7.5")
    }
  2. GoogleFont.Provider را با اعتبارنامه فونت های Google راه اندازی کنید:
    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 را در فایل 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 composable خود پیکربندی کنید:

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

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

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

هشدارها

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

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

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

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

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

برای پیشینه بیشتر درباره فونت های متغیر، به Google Fonts Knowledge ، کل کاتالوگ فونت های متغیر موجود، و جدول محورهای پشتیبانی شده برای هر فونت مراجعه کنید.

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

سه متن مختلف که همگی تنظیمات فونت های مختلف را به نمایش می گذارند.
شکل 2. فونت متغیر در سه پیکربندی مختلف اعمال می شود.

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

فونت ها همچنین می توانند محورهای سفارشی داشته باشند. اینها در خود فایل فونت تعریف شده اند. برای مثال، فونت Roboto Flex دارای محور ascender height ( "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. متنی که محورهای سفارشی تنظیم شده بر روی فونت های متغیر را نشان می دهد.

منابع اضافی

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

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}