تالیف و کتابخانه های دیگر

شما می‌توانید از کتابخانه‌های مورد علاقه خود در Compose استفاده کنید. این بخش نحوه‌ی ترکیب چند مورد از مفیدترین کتابخانه‌ها را شرح می‌دهد.

فعالیت

برای استفاده از Compose در یک activity، باید از ComponentActivity استفاده کنید، یک زیرکلاس از Activity که LifecycleOwner و کامپوننت‌های مناسب را برای Compose فراهم می‌کند. همچنین APIهای اضافی را ارائه می‌دهد که کد شما را از override کردن متدها در کلاس activity شما جدا می‌کند. Activity Compose این APIها را در اختیار composableها قرار می‌دهد به طوری که override کردن متدهای خارج از composableهای شما یا بازیابی یک نمونه Activity صریح دیگر لازم نیست. علاوه بر این، این APIها تضمین می‌کنند که فقط یک بار مقداردهی اولیه می‌شوند، از recomposition جان سالم به در می‌برند و در صورت حذف composable از composition، به درستی پاک می‌شوند.

نتیجه فعالیت

API rememberLauncherForActivityResult() به شما این امکان را می‌دهد که نتیجه‌ای از یک activity در composable خود دریافت کنید :

@Composable
fun GetContentExample() {
    var imageUri by remember { mutableStateOf<Uri?>(null) }
    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
        imageUri = uri
    }
    Column {
        Button(onClick = { launcher.launch("image/*") }) {
            Text(text = "Load Image")
        }
        Image(
            painter = rememberAsyncImagePainter(imageUri),
            contentDescription = "My Image"
        )
    }
}

این مثال یک قرارداد ساده GetContent() نشان می‌دهد. با لمس دکمه، درخواست اجرا می‌شود. لامبدای انتهایی برای rememberLauncherForActivityResult() پس از انتخاب تصویر توسط کاربر و بازگشت به اکتیویتی اجرا می‌شود. این کار تصویر انتخاب شده را با استفاده از تابع rememberImagePainter() در Coil بارگذاری می‌کند.

هر زیرکلاسی از ActivityResultContract می‌تواند به عنوان اولین آرگومان برای rememberLauncherForActivityResult() استفاده شود. این بدان معناست که می‌توانید از این تکنیک برای درخواست محتوا از چارچوب و در سایر الگوهای رایج استفاده کنید. همچنین می‌توانید قراردادهای سفارشی خود را ایجاد کرده و از آنها با این تکنیک استفاده کنید.

درخواست مجوزهای زمان اجرا

همان API مربوط به Activity Result و rememberLauncherForActivityResult() که در بالا توضیح داده شد، می‌توانند برای درخواست مجوزهای زمان اجرا با استفاده از قرارداد RequestPermission برای یک مجوز واحد یا قرارداد RequestMultiplePermissions برای چندین مجوز استفاده شوند.

کتابخانه Accompanist Permissions همچنین می‌تواند به عنوان یک لایه بالاتر از آن APIها برای نگاشت وضعیت فعلی اعطا شده برای مجوزها به وضعیتی که رابط کاربری Compose شما می‌تواند از آن استفاده کند، استفاده شود.

مدیریت دکمه بازگشت سیستم

برای ارائه ناوبری برگشت سفارشی و لغو رفتار پیش‌فرض دکمه برگشت سیستم از درون composable خود، composable شما می‌تواند از یک BackHandler برای رهگیری آن رویداد استفاده کند:

var backHandlingEnabled by remember { mutableStateOf(true) }
BackHandler(backHandlingEnabled) {
    // Handle back press
}

آرگومان اول کنترل می‌کند که آیا BackHandler در حال حاضر فعال است یا خیر؛ شما می‌توانید از این آرگومان برای غیرفعال کردن موقت handler خود بر اساس وضعیت کامپوننت خود استفاده کنید. اگر کاربر یک رویداد back سیستمی را فعال کند و BackHandler در حال حاضر فعال باشد، lambda بعدی فراخوانی خواهد شد.

ViewModel

اگر از کتابخانه‌ی Architecture Components ViewModel استفاده می‌کنید، می‌توانید با فراخوانی تابع viewModel() از هر کامپوننتی به ViewModel دسترسی داشته باشید. وابستگی زیر را به فایل Gradle خود اضافه کنید:

گرووی

dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5'
}

کاتلین

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5")
}

سپس می‌توانید از تابع viewModel() در کد خود استفاده کنید.

class MyViewModel : ViewModel() { /*...*/ }

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    // use viewModel here
}

viewModel() یک ViewModel موجود را برمی‌گرداند یا یک ViewModel جدید ایجاد می‌کند. به طور پیش‌فرض، ViewModel برگردانده شده به activity، fragment یا navigation destination که آن را در بر می‌گیرد، محدود می‌شود و تا زمانی که scope فعال باشد، حفظ می‌شود.

برای مثال، اگر composable در یک activity استفاده شود، viewModel() تا زمانی که activity تمام نشده یا process از بین نرفته باشد، همان نمونه را برمی‌گرداند.

class MyViewModel : ViewModel() { /*...*/ }
// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    // Returns the same instance as long as the activity is alive,
    // just as if you grabbed the instance from an Activity or Fragment
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

@Composable
fun MyScreen2(
    viewModel: MyViewModel = viewModel() // Same instance as in MyScreen
) { /* ... */ }

دستورالعمل‌های استفاده

شما معمولاً به نمونه‌های ViewModel در composableهای سطح صفحه دسترسی پیدا می‌کنید، یعنی نزدیک به یک composable ریشه که از یک activity، fragment یا مقصد یک گراف Navigation فراخوانی می‌شود. دلیل این امر این است که ViewModel ها، به طور پیش‌فرض، به آن اشیاء سطح صفحه محدود می‌شوند. برای اطلاعات بیشتر در مورد چرخه حیات و دامنه ViewModel ، اینجا را بخوانید.

سعی کنید از ارسال نمونه‌های ViewModel به سایر composableها خودداری کنید، زیرا این کار می‌تواند آزمایش آن composableها را دشوارتر کند و پیش‌نمایش‌ها را خراب کند. در عوض، فقط داده‌ها و توابعی را که به آنها نیاز دارند به عنوان پارامتر ارسال کنید.

شما می‌توانید از نمونه‌های ViewModel برای مدیریت وضعیت Composableهای سطح زیر صفحه نمایش استفاده کنید، با این حال، از چرخه حیات و دامنه ViewModel آگاه باشید. اگر Composable مستقل باشد، ممکن است بخواهید از Hilt برای تزریق ViewModel استفاده کنید تا از نیاز به ارسال وابستگی‌ها از Composableهای والد جلوگیری کنید.

اگر ViewModel شما وابستگی‌هایی داشته باشد، viewModel() یک ViewModelProvider.Factory اختیاری را به عنوان پارامتر می‌گیرد.

برای اطلاعات بیشتر در مورد ViewModel در Compose و نحوه استفاده از نمونه‌ها با کتابخانه Navigation Compose یا فعالیت‌ها و قطعات، به مستندات Interoperability مراجعه کنید.

جریان‌های داده

Compose با افزونه‌هایی برای محبوب‌ترین راه‌حل‌های مبتنی بر جریان در اندروید ارائه می‌شود. هر یک از این افزونه‌ها توسط یک مصنوع متفاوت ارائه می‌شوند:

  • LiveData.observeAsState() در مصنوع androidx.compose.runtime:runtime-livedata:$composeVersion گنجانده شده است.
  • Flow.collectAsState() به وابستگی‌های اضافی نیاز ندارد.
  • Observable.subscribeAsState() در مصنوع androidx.compose.runtime:runtime-rxjava2:$composeVersion یا androidx.compose.runtime:runtime-rxjava3:$composeVersion گنجانده شده است.

این مصنوعات به عنوان یک شنونده ثبت می‌شوند و مقادیر را به عنوان یک State نمایش می‌دهند. هر زمان که مقدار جدیدی منتشر می‌شود، Compose آن بخش‌هایی از رابط کاربری را که در آن از آن state.value استفاده شده است، دوباره ترکیب می‌کند. برای مثال، در این کد، ShowData هر بار که exampleLiveData مقدار جدیدی منتشر می‌کند، دوباره ترکیب می‌شود.

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val dataExample = viewModel.exampleLiveData.observeAsState()

    // Because the state is read here,
    // MyScreen recomposes whenever dataExample changes.
    dataExample.value?.let {
        ShowData(dataExample)
    }
}

عملیات ناهمزمان در Compose

Jetpack Compose به شما امکان می‌دهد عملیات ناهمزمان را با استفاده از کوروتین‌ها از درون composableهای خود اجرا کنید.

برای اطلاعات بیشتر به APIهای LaunchedEffect ، produceState و rememberCoroutineScope در مستندات عوارض جانبی مراجعه کنید.

کامپوننت Navigation از برنامه‌های Jetpack Compose پشتیبانی می‌کند. برای اطلاعات بیشتر به بخش «پیمایش با Compose» و «انتقال ناوبری Jetpack به Navigation Compose» مراجعه کنید.

هیلت

Hilt راهکار پیشنهادی برای تزریق وابستگی در برنامه‌های اندروید است و به طور یکپارچه با Compose کار می‌کند.

تابع viewModel() که در بخش ViewModel به آن اشاره شد، به‌طور خودکار از ViewModelی که Hilt با حاشیه‌نویسی @HiltViewModel می‌سازد، استفاده می‌کند. ما مستنداتی را با اطلاعاتی در مورد ادغام ViewModel در Hilt ارائه کرده‌ایم.

@HiltViewModel
class MyViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: ExampleRepository
) : ViewModel() { /* ... */ }

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

دسته و جهت‌یابی

Hilt همچنین با کتابخانه‌ی Navigation Compose ادغام می‌شود. وابستگی‌های اضافی زیر را به فایل Gradle خود اضافه کنید:

گرووی

dependencies {
    implementation 'androidx.hilt:hilt-navigation-compose:1.3.0'
}

کاتلین

dependencies {
    implementation("androidx.hilt:hilt-navigation-compose:1.3.0")
}

هنگام استفاده از Navigation Compose، همیشه از تابع composable hiltViewModel برای دریافت نمونه‌ای از ViewModel حاشیه‌نویسی‌شده @HiltViewModel خود استفاده کنید. این روش با fragmentها یا activityهایی که با @AndroidEntryPoint حاشیه‌نویسی شده‌اند، کار می‌کند.

برای مثال، اگر ExampleScreen یک مقصد در یک گراف ناوبری باشد، hiltViewModel() را فراخوانی کنید تا نمونه‌ای از ExampleViewModel که به مقصد مورد نظر محدود شده است را همانطور که در قطعه کد زیر نشان داده شده است، دریافت کنید:

// import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun MyApp() {
    val navController = rememberNavController()
    val startRoute = "example"
    NavHost(navController, startDestination = startRoute) {
        composable("example") { backStackEntry ->
            // Creates a ViewModel from the current BackStackEntry
            // Available in the androidx.hilt:hilt-navigation-compose artifact
            val viewModel = hiltViewModel<MyViewModel>()
            MyScreen(viewModel)
        }
        /* ... */
    }
}

اگر نیاز دارید نمونه‌ای از ViewModel که به مسیرهای ناوبری یا گراف ناوبری محدود شده است را بازیابی کنید، از تابع ترکیبی hiltViewModel استفاده کنید و backStackEntry مربوطه را به عنوان پارامتر ارسال کنید:

// import androidx.hilt.navigation.compose.hiltViewModel
// import androidx.navigation.compose.getBackStackEntry

@Composable
fun MyApp() {
    val navController = rememberNavController()
    val startRoute = "example"
    val innerStartRoute = "exampleWithRoute"
    NavHost(navController, startDestination = startRoute) {
        navigation(startDestination = innerStartRoute, route = "Parent") {
            // ...
            composable("exampleWithRoute") { backStackEntry ->
                val parentEntry = remember(backStackEntry) {
                    navController.getBackStackEntry("Parent")
                }
                val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry)
                ExampleWithRouteScreen(parentViewModel)
            }
        }
    }
}

صفحه بندی

کتابخانه Paging بارگذاری تدریجی داده‌ها را برای شما آسان‌تر می‌کند و در Compose پشتیبانی می‌شود. صفحه انتشار Paging حاوی اطلاعاتی در مورد وابستگی اضافی paging-compose است که باید به پروژه و نسخه آن اضافه شود.

در اینجا مثالی از APIهای Compose کتابخانه Paging آورده شده است:

@Composable
fun MyScreen(flow: Flow<PagingData<String>>) {
    val lazyPagingItems = flow.collectAsLazyPagingItems()
    LazyColumn {
        items(
            lazyPagingItems.itemCount,
            key = lazyPagingItems.itemKey { it }
        ) { index ->
            val item = lazyPagingItems[index]
            Text("Item is $item")
        }
    }
}

برای اطلاعات بیشتر در مورد استفاده از صفحه‌بندی در Compose ، مستندات Lists and grids را بررسی کنید.

نقشه‌ها

شما می‌توانید از کتابخانه Maps Compose برای ارائه نقشه‌های گوگل در برنامه خود استفاده کنید. در اینجا یک مثال کاربردی آورده شده است:

@Composable
fun MapsExample() {
    val singapore = LatLng(1.35, 103.87)
    val cameraPositionState = rememberCameraPositionState {
        position = CameraPosition.fromLatLngZoom(singapore, 10f)
    }
    GoogleMap(
        modifier = Modifier.fillMaxSize(),
        cameraPositionState = cameraPositionState
    ) {
        Marker(
            state = remember { MarkerState(position = singapore) },
            title = "Singapore",
            snippet = "Marker in Singapore"
        )
    }
}

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