المكونات الأساسية والتنسيقات

تقدّم Jetpack Compose طلبًا لتنفيذ التصميم المتعدد الأبعاد، وهو نظام تصميم شامل لإنشاء الواجهات الرقمية. تتوفر المكونات الأساسية (الأزرار والبطاقات ومفاتيح التبديل، وما إلى ذلك) والتنسيقات مثل Scaffold كدوال قابلة للإنشاء.

المكوّنات الأساسية هي عناصر أساسية تفاعلية لإنشاء واجهة مستخدم. يقدّم Compose عددًا من هذه المكوّنات المبتكرة. لمعرفة الإصدارات المتوفّرة، يمكنك الاطّلاع على مرجع Material Material API.

تستخدم "مكوّنات المواد" القيم التي توفّرها MaterialTheme في تطبيقك:

@Composable
fun MyApp() {
    MaterialTheme {
        // Material Components like Button, Card, Switch, etc.
    }
}

لمعرفة المزيد من المعلومات حول هذه المواضيع، يمكنك الاطّلاع على أنظمة التصميم في أدلة الإنشاء.

خانات المحتوى

مكوّنات المواد الأساسية التي تتيح المحتوى الداخلي (التصنيفات النصية والرموز وما إلى ذلك) تميل إلى تقديم "خانات إعلانية"، وهي دالة lambda عامة تقبل المحتوى القابل للإنشاء، بالإضافة إلى الثوابت العامة، مثل الحجم والبطانة، لإتاحة وضع محتوى داخلي مطابق لمواصفات المواد.

من الأمثلة على ذلك Button:

Button(
    onClick = { /* ... */ },
    // Uses ButtonDefaults.ContentPadding by default
    contentPadding = PaddingValues(
        start = 20.dp,
        top = 12.dp,
        end = 20.dp,
        bottom = 12.dp
    )
) {
    // Inner content including an icon and a text label
    Icon(
        Icons.Filled.Favorite,
        contentDescription = "Favorite",
        modifier = Modifier.size(ButtonDefaults.IconSize)
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
}

الشكل 1. Button باستخدام الفتحة content وال المساحة المتروكة التلقائية (يسارًا) وButton باستخدام الخانة content التي توفّر contentPadding مخصّص (على اليمين).

تحتوي السمة Button على فتحة content lambda لاحقة عامة، تستخدِم RowScope لتنسيق المحتوى القابل للإنشاء على التوالي. تتضمن المَعلمة أيضًا معلَمة contentPadding لتطبيق المساحة المتروكة على المحتوى الداخلي. يمكنك استخدام الثوابت التي تم تقديمها من خلال ButtonDefaults أو قيم مخصّصة.

مثال آخر: ExtendedFloatingActionButton:

ExtendedFloatingActionButton(
    onClick = { /* ... */ },
    icon = {
        Icon(
            Icons.Filled.Favorite,
            contentDescription = "Favorite"
        )
    },
    text = { Text("Like") }
)

الشكل 2: ExtendedFloatingActionButton باستخدام الخانات icon وtext.

بدلاً من دالة content lambda العامة، يحتوي ExtendedFloatingActionButton على خانتَين للتصنيف icon وtext. على الرغم من أنّ كل خانة تتوافق مع محتوى عام قابل للإنشاء، يتم رأي المكوِّن حول كيفية تصميم هذه الأجزاء من المحتوى الداخلي. يتعامل مع المساحة المتروكة والمحاذاة والحجم داخليًا.

سقالة

توفّر ميزة "الإنشاء" تنسيقات مناسبة لدمج المكونات الأساسية في أنماط الشاشة الشائعة. توفّر العناصر القابلة للإنشاء، مثل Scaffold، خاناتًا لمختلف المكوّنات وعناصر الشاشة الأخرى.

محتوى الشاشة

يحتوي Scaffold على فتحة lambda عامة واحدة (content). تتلقّى دالة lambda مثيلاً من الرمز PaddingValues الذي يجب تطبيقه على جذر المحتوى، مثلاً من خلال Modifier.padding، وذلك لتعويض الشريطَين العلوي والسفلي، في حال توفّرهما.

Scaffold(/* ... */) { contentPadding ->
    // Screen content
    Box(modifier = Modifier.padding(contentPadding)) { /* ... */ }
}

أشرطة التطبيقات

يوفر Scaffold خانات لشريط التطبيق العلوي أو شريط التطبيق السفلي. يتم التعامل مع موضع العارضات القابلة للإنشاء داخليًا.

يمكنك استخدام الخانة topBar وTopAppBar:

Scaffold(
    topBar = {
        TopAppBar(title = {
            Text("My App")
        })
    }
) { contentPadding ->
    // Screen content
}

يمكنك استخدام الخانة bottomBar وBottomAppBar:

Scaffold(
    bottomBar = {
        BottomAppBar { /* Bottom app bar content */ }
    }
) { contentPadding ->
    // Screen content
}

ويمكن استخدام هذه الخانات لمكوّنات المادة الأخرى، مثل BottomNavigation. يمكنك أيضًا استخدام تركيبات مخصّصة، مثل إلقاء نظرة على شاشة الإعداد من نموذج البومة.

أزرار الإجراءات العائمة

توفّر ميزة Scaffold خانة زر الإجراء العائم.

يمكنك استخدام الخانة floatingActionButton وFloatingActionButton:

Scaffold(
    floatingActionButton = {
        FloatingActionButton(onClick = { /* ... */ }) {
            /* FAB content */
        }
    }
) { contentPadding ->
    // Screen content
}

تتم معالجة موضع الإعلان السفلي لوحدة تحكّم الإجراء الرئيسي تلقائيًا. يمكنك استخدام المعلَمة floatingActionButtonPosition لضبط الموضع الأفقي:

Scaffold(
    floatingActionButton = {
        FloatingActionButton(onClick = { /* ... */ }) {
            /* FAB content */
        }
    },
    floatingActionButtonPosition = FabPosition.Center
) { contentPadding ->
    // Screen content
}

أشرطة ملونة

توفّر السمة Scaffold وسيلة لعرض أشرطة الإعلام.

يتم توفير ذلك من خلال SnackbarHost، الذي يتضمّن سمة SnackbarHostState. توفّر السمة SnackbarHostState إمكانية الوصول إلى دالة showSnackbar. تتطلب وظيفة التعليق هذه CoroutineScope، على سبيل المثال، استخدام rememberCoroutineScope، ويمكن طلبها استجابةً لأحداث واجهة المستخدم لعرض Snackbar ضمن Scaffold.

val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
    snackbarHost = {
        SnackbarHost(hostState = snackbarHostState)
    },
    floatingActionButton = {
        ExtendedFloatingActionButton(
            text = { Text("Show snackbar") },
            icon = { Icon(Icons.Filled.Image, contentDescription = "") },
            onClick = {
                scope.launch {
                    snackbarHostState.showSnackbar("Snackbar")
                }
            }
        )
    }
) { contentPadding ->
    // Screen content
}

يمكنك توفير إجراء اختياري وتعديل مدة Snackbar. تقبل الدالة snackbarHostState.showSnackbar المعلّمتَين الإضافيتَين actionLabel وduration، وتعرض SnackbarResult.

val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
    snackbarHost = {
        SnackbarHost(hostState = snackbarHostState)
    },
    floatingActionButton = {
        ExtendedFloatingActionButton(
            text = { Text("Show snackbar") },
            icon = { Icon(Icons.Filled.Image, contentDescription = "") },
            onClick = {
                scope.launch {
                    val result = snackbarHostState
                        .showSnackbar(
                            message = "Snackbar",
                            actionLabel = "Action",
                            // Defaults to SnackbarDuration.Short
                            duration = SnackbarDuration.Indefinite
                        )
                    when (result) {
                        SnackbarResult.ActionPerformed -> {
                            /* Handle snackbar action performed */
                        }
                        SnackbarResult.Dismissed -> {
                            /* Handle snackbar dismissed */
                        }
                    }
                }
            }
        )
    }
) { contentPadding ->
    // Screen content
}

يمكنك توفير Snackbar مخصّص باستخدام المعلَمة snackbarHost. اطّلِع على SnackbarHost API reference docs للحصول على مزيد من المعلومات.

الأدراج

ModalNavigationDrawer هو درج التنقل الخاص بالتصميم المتعدد الأبعاد.

يمكنك استخدام الخانة drawerContent لتوفير ModalDrawerSheet وتوفير محتوى اللائحة:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("Drawer title", modifier = Modifier.padding(16.dp))
            Divider()
            NavigationDrawerItem(
                label = { Text(text = "Drawer Item") },
                selected = false,
                onClick = { /*TODO*/ }
            )
            // ...other drawer items
        }
    }
) {
    // Screen content
}

تقبل ModalNavigationDrawer عددًا من معلمات الدرج الإضافية. على سبيل المثال، يمكنك تبديل ما إذا كان اللائحة تستجيب لسحب العناصر باستخدام المَعلمة gesturesEnabled أم لا:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            // Drawer contents
        }
    },
    gesturesEnabled = false
) {
    // Screen content
}

يتم فتح اللائحة وإغلاقها آليًا من خلال DrawerState. يجب تمرير DrawerState إلى ModalNavigationDrawer باستخدام المعلَمة drawerState. توفّر خدمة DrawerState إمكانية الوصول إلى الدالتَين open وclose، بالإضافة إلى السمات ذات الصلة بحالة الدرج الحالية. تتطلب دوال التعليق هذه CoroutineScope، على سبيل المثال، استخدام rememberCoroutineScope، ويمكن طلبها استجابةً لأحداث واجهة المستخدم.

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        ModalDrawerSheet { /* Drawer content */ }
    },
) {
    Scaffold(
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Show drawer") },
                icon = { Icon(Icons.Filled.Add, contentDescription = "") },
                onClick = {
                    scope.launch {
                        drawerState.apply {
                            if (isClosed) open() else close()
                        }
                    }
                }
            )
        }
    ) { contentPadding ->
        // Screen content
    }
}

البطاقات السفلية

إذا كنت تريد تنفيذ ورقة سفلية، يمكنك استخدام ModalBottomSheet الإنشاء.

يمكنك استخدام الخانة content التي تستخدم ColumnScope لتنسيق محتوى جدول بيانات قابل للإنشاء في عمود:

ModalBottomSheet(onDismissRequest = { /* Executed when the sheet is dismissed */ }) {
    // Sheet content
}

يتم توسيع جدول البيانات وتصغيره آليًا من خلال SheetState. يمكنك استخدام rememberSheetState لإنشاء مثيل SheetState يجب تمريره إلى ModalBottomSheet باستخدام المَعلمة sheetState. SheetState توفّر إمكانية الوصول إلى الدالتَين show وcollapse، بالإضافة إلى المواقع ذات الصلة بحالة الورقة الحالية. تتطلب هذه الدوال المعلّقة CoroutineScope، على سبيل المثال، استخدام rememberCoroutineScope، ويمكن طلبها استجابةً لأحداث واجهة المستخدم. احرص على إزالة ModalBottomSheet من المقطوعة الموسيقية عند إخفاء البطاقة السفلية.

val sheetState = rememberModalBottomSheetState()
val scope = rememberCoroutineScope()
var showBottomSheet by remember { mutableStateOf(false) }
Scaffold(
    floatingActionButton = {
        ExtendedFloatingActionButton(
            text = { Text("Show bottom sheet") },
            icon = { Icon(Icons.Filled.Add, contentDescription = "") },
            onClick = {
                showBottomSheet = true
            }
        )
    }
) { contentPadding ->
    // Screen content

    if (showBottomSheet) {
        ModalBottomSheet(
            onDismissRequest = {
                showBottomSheet = false
            },
            sheetState = sheetState
        ) {
            // Sheet content
            Button(onClick = {
                scope.launch { sheetState.hide() }.invokeOnCompletion {
                    if (!sheetState.isVisible) {
                        showBottomSheet = false
                    }
                }
            }) {
                Text("Hide bottom sheet")
            }
        }
    }
}