فصل دو، قسمت اول:
ما قراره تو این فصل رابط کاربری اپ اندرویدی مون رو با jetpack compose توسعه بدیم. کامپوز declarative هستش، کد خیلی کمتری نسبت به UI سیستم قبلی اندروید میخواد برای پیاده سازی رابط کاربری، منعطفه و ...
نکته: این کتاب بصورت سطحی درباره jetpack compose حرف زده و چون ما یه بخش مجزا برای compose داریم، خیلی روی اینا مانُور نمیدیم و سریع میریم سراغ پیاده سازی UI.
اگه پروژه تون رو آماده کردید، برید MainActivity رو باز کنید، بجای setContentView که توش layout xml مون رو inflate میکردیم، setContent قرار گرفته؛ setContent یه extension فانکشن روی کلاس ComponentActivity. این متد قاعدتا composable هستش چون UI مون رو توش قرار میدیم.
خب ما قراره یه اپی رو توسعه بدیم که کاربرا بتونن چندین منطقه زمانی(time zone) رو انتخاب کنن و یه سری زمان های مناسبی رو برای مثلا جلسه پیدا کنن. این صفحه اول اپ مونه:
میبینین که تو هر آیتم ما منطقه زمانی محلی، زمان و تاریخ رو داریم و هر کدوم از کاربر ها location خاصی دارن یکی لندنه یکی دیگه لس آنجلس و.. کاربر سعی میکنه تا ساعت مناسبی برای جلسه پیدا کنه تا همه با اون زمان جور بشن.
وقتی کاربر بخواد یه منطقه زمانی دیگه رو اضافه کنه، باید رو floating action button کلیک کنه و یه dialog براش ظاهر میشه برای انتخاب هر منطقه زمانی ای که میخواد:
صفحه بعدی صفحه جستجو هستش که کاربر میتونه یه ساعت شروع و پایان بذاره برای جلسشون و...:
وقت روی دکمه search کلیک کرد یه همچین چیزی میاد:
شما قبلا برای تعریف theme برنامه تون از فایل نین و نینی استفاده میکردید، ولی توی compose میتونین از کلاس MaterialTheme استفاده کنید برای رنگ، فونت و شکل ها.
خب، توی ماژول androidApp کنار MainActivity یه پکیج بنام theme بسازید و توش هم یه فایلی بنام Colors.kt درست کنید و اینا رو توش قرار بدید:
import androidx.compose.ui.graphics.Color val primaryColor = Color(0xFF1e88e5) val primaryLightColor = Color(0xFF6ab7ff) val primaryDarkColor = Color(0xFF005cb2) val secondaryColor = Color(0xFF26a69a) val secondaryLightColor = Color(0xFF64d8cb) val secondaryDarkColor = Color(0xFF00766c) val primaryTextColor = Color(0xFF000000) val secondaryTextColor = Color(0xFF000000)
اینا رنگ های اولیه(primary) و ثانویه(secondary) برنامه تون هستش.
خب یه فایل دیگه توی همین پکیج بنام Typography.kt بسازید و اینا رو توش قرار بدید:
import androidx.compose.material.Typography import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp // 1 val typography = Typography( // 2 h1 = TextStyle( // 3 fontFamily = FontFamily.SansSerif, // 4 fontSize = 24. sp, // 5 fontWeight = FontWeight.Bold, // 6 color = Color.White ), h2 = TextStyle( fontFamily = FontFamily.SansSerif, fontSize = 20. sp, color = Color.White ), h3 = TextStyle( fontFamily = FontFamily.SansSerif, fontSize = 12. sp, color = Color.White ), h4 = TextStyle( fontFamily = FontFamily.SansSerif, fontSize = 10. sp, color = Color.White ) )
1- متغیر typography یه instance هستش از کلاس تایپوگرافی کامپوز.
2- این h1 از پیش تعریف شده رو override میکنیم
3- فونت family رو مشخص میکنیم که اینجا فونت مون از خانواده SansSerif هستش.
4- اندازه فونت
5- وزن(weight) فونت
6- اینم رنگ فونته
شما میتونین ویژگی های دیگه مثل فاصله بین حروف(letter spacing) و ... رو برای TextStyle تنظیم کنین.
خب یه فایل دیگه تو این پکیج ایجاد کنید به اسن AppTheme.kt و اینا رو اضافه کنید:
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material.MaterialTheme import androidx.compose.material.darkColors import androidx.compose.material.lightColors import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color @Composable fun AppTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() -> Unit) { // TODO: Add Colors }
این فانکشن یه پارامتر اختیاری داره برای تنظیم کردن حالت dark و چک میکنه آیا سیستم تو حالت dark هست یا خیر. پارامتر دومی هم یه composable فانکشن برای نشون دادن تم. خب بیاید رنگ هارو برای تم روشن و تیره تنظیم کنیم:
val colors = if (darkTheme) { darkColors() .copy( primary = primaryDarkColor, primaryVariant = primaryLightColor, secondary = secondaryDarkColor, secondaryVariant = secondaryLightColor, onPrimary = Color.White, ) } else { lightColors() .copy( primary = primaryColor, primaryVariant = primaryLightColor, secondary = secondaryColor, secondaryVariant = secondaryLightColor, onPrimary = Color.Black, ) } // TODO: Add Theme
فانکشن های lightColors و darkColors یه کلاس Colors برگشت میده. این کد ها رو با
// TODO: Add Theme
عوض کنید:
MaterialTheme( colors = colors, typography = typography, content = content )
این MaterialTheme رو اعمال میکنه به پروژه با رنگ ها و تایپوگرافی ای که خودمون تنظیم کرده بودیم
چندتا تایپ لازم داریم که بعدا توی پروژه ازش استفاده میکنیم. برید توی پوشه UI و یه فایل به اسم یتیمی Types.kt و اینا رو قرار بدید:
import androidx.compose.runtime.Composable // 1 typealias OnAddType = (List < String > ) -> Unit // 2 typealias onDismissType = () -> Unit // 3 typealias composeFun = @Composable() -> Unit // 4 typealias topBarFun = @Composable(Int) -> Unit // 5 @Composable fun emptyComposable() {}
نکته: توی بهتر بنویسیم بعدی typealias رو توضیح میدم.
1- یه نام مستعار به نام onaddType تعریف میکنه که لیستی از رشته ها رو به شما میده و چیزی هم برنمیگردونه.
2- نام مستعار برای بستن dialog
3- یه composable فاکنشن رو تعریف میکنه
4- یه فانکشن که یه integer میگیره
5- یه composable خالی
توی ماژول androidApp توی پوشه UI یه فایل به اسم MainView.kt بسازید. با ساختن یه سری متغیر و کلاس های helper شروع میکنیم. اول این import ها رو به فایل اضافه کنید(برای ذخیره وقت):
import androidx.compose.foundation.layout.padding import androidx.compose.material.BottomNavigation import androidx.compose.material.BottomNavigationItem import androidx.compose.material.FloatingActionButton import androidx.compose.material.Icon import androidx.compose.material.Scaffold import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Language import androidx.compose.material.icons.filled.Place import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp import com.raywenderlich.findtime.android.theme.AppTheme
برای پیگیری دو screen تون،یه sealed کلاس بنام Screen ایجاد کنید:
sealed class Screen(val title: String) { object TimeZonesScreen: Screen("Timezones") object FindTimeScreen: Screen("Find Time") }
توش دوتا صفحه TimeZonesScreen و FindTimeScreen تعریف کردیم بهمراه title شون. قدم بعدی تعریف یه کلاس برای handle کردن آیتم bottom navigation مون:
data class BottomNavigationItem( val route: String, val icon: ImageVector, val iconContentDescription: String )
یه مسیر یا route(برای navigate کردن بین صفحه ها بعدا باهاش آشنا میشید)، یه آیکون و محتوای توضیحات داره. قدم بعدی ساختن یه متغیر با دوتا آیتم هستش برای bottom navigation:
val bottomNavigationItems = listOf( BottomNavigationItem( Screen.TimeZonesScreen.title, Icons.Filled.Language, "Timezones" ), BottomNavigationItem( Screen.FindTimeScreen.title, Icons.Filled.Place, "Find Time" ) )
ااز متریال آیکون و title screen ها استفاده میکنه. خب حالا یه composable بنام MainView بسازید:
// 1 @Composable // 2 fun MainView(actionBarFun: topBarFun = { emptyComposable() }) { // 3 val showAddDialog = remember { mutableStateOf(false) } // 4 val currentTimezoneStrings = remember { SnapshotStateList < String > () } // 5 val selectedIndex = remember { mutableStateOf(0) } // 6 AppTheme { // TODO: Add Scaffold } }
2- این فانکشن یه فانکشنی میگیره برای topbar (همون toolbar).
3- اِستیت(وضعیت) نشون دادن dialog رو نگه میداره.
4- استیتی که شامل یه لیستی از منطقه زمانی فعلی رو بصورت رشته نگه میداره.
5- برای حفظ وضعیت index انتخاب شده از فانکشن ها remember و mutableStateOf استفاده میکنیم.
6- از تمی که ساختیم استفاده میکنه.
فک کنم برای این پست کافی باشه. میدونم برنامه این هفته یکم بهم خورده ولی چهارشنبه بجای null این فصل رو تموم میکنیم.
و آخر اگه به باگی برخوردید، تو کامنت ها به اشتراک بزارین تا حلش کنیم.