جت‌پک کامپوز در اندروید: استفاده از لایه های Box، Row و Column

جت‌پک کامپوز در اندروید: استفاده از لایه های Box، Row و Column

لایه های کامپوزی (Composable Layouts)

در جت‌پک کامپوز میتونیم نحوه چیدمان Composable ها و محل قرارگیری چیدمان ها رو مشخص کنیم؛ برای این کار باید از لایه های کامپوزی (Composable Layouts) استفاده کنیم؛ لایه های کامپوزی میتونن یک یا چند Composable رو نگهدارن، هر لایه چیدمان خاص خودشو داره و میتونیم محل قرار گیری چیدمان Composable ها رو در لایه مشخص کنیم.

لایه های کامپوزی خودشون Composable هستن و میتونیم یک لایه کامپوزی رو به عنوان Composable به لایه کامپوزی دیگه اضافه کنیم.

سه تا از لایه های کامپوزی عبارتند از Box, Row و Column و این سه مبنا و اساس بسیاری از لایه های کامپوزی دیگه هستند.

استفاده از Box

Composable ها در لایه Box به صورت استک روی هم میوفتن، میتونیم Composable ها رو در 9 ناحیه مختلف در Box قرار بدیم؛ در تصویر زیر محل قرارگرفتن Composable ها در Box با رنگ قرمز مشخص شده است.

محل قرارگیری Composable ها در Box
محل قرارگیری Composable ها در Box

فرم کلی:

@Composable
fun Box(modifier: Modifier = Modifier, contentAlignment = Alignment.TopStart, content: @Composable BoxScope.() -> Unit)
                

با استفاده از Modifier میتونیم لایه رو سفارشی‌سازی کنیم، با مقداردهی contentAlignment میتونیم ناحیه قرار‌گیر گرفتن Composable های داخل Box رو مشخص کنیم، مقدار پیشفرض Alignment برابر با Alignment.TopStart است و با ایجاد یک تابع لیترال برای content میتونیم Composable ها رو به Box اضافه کنیم.

در مثال زیر میخوایم متن Hello Android رو در Box نمایش بدیم.

@Composable
fun HelloAndroidCenter(modifier: Modifier = Modifier){
    Box(modifier = modifier, contentAlignment = Alignment.Center){
        Text("Hello Android", fontSize = 36.sp)
    }
}
                

متغیر contentAlignment در Box دارای 9 مقدار مختلف است که با این 9 مقدار مطابق عکس بالا میتونیم Composable ها رو در 9 ناحیه مختلف داخل Box قرار بدیم؛ در جدول زیر این 9 مقدار شرح داده شده است.

Alignment
TopStart Composable ها رو در بالا، ابتدای لایه قرار می‌ده.
TopCenter Composable ها رو در بالا وسط قرار میده.
TopEnd Composable ها رو در بالا، انتهای لایه قرار می‌ده.
CenterStart Composable ها رو در وسط و ابتدای افقی لایه قرار می‌ده.
Center Composable ها رو در وسط لایه قرار‌ می‌ده.
CenterEnd Composable ها رو در وسط انتهای لایه قرار می‌ده.
BottomStart Composable ها رو در پایین، ابتدای لایه قرار می‌ده.
BottomCenter Composable ها رو در پایین، وسط لایه قرار میده.
BottomEnd Composable ها رو در پایین، انتهای لایه قرار میده.

یک تابع اکستنشن به نام align در Modifier برای BoxScope تعریف شده که با استفاده از تابع میتونیم محل قرارگیری هر Composable در Box رو به صورت جدا مشخص کنیم.

@Composable
fun MyComposableBox(){
    Box{
        Text(text = "First Text In Column", modifier = Modifier.align(Alignment.TopStart))
        Text(text = "Second Text In Column", modifier = Modifier.align(Alignment.TopEnd))
        Text(text = "Third Text In Column", modifier = Modifier.align(Alignment.Center))
    }
}
                

در مثال زیر میخوایم یک متن رو در بالا وسط، یک متن رو در وسط و یک متن رو در پایین انتهای Box نمایش بدیم.

@Composable
fun MyText(modifier: Modifier = Modifier){
    Box(modifier.fillMaxSize()){
        Text(text = "Hello Android!", fontSize = 50.sp, modifier = Modifier.padding(16.dp).align(Alignment.TopCenter))
        Text(text = "From Compose", fontSize = 30.sp, modifier = Modifier.padding(16.dp).align(Alignment.Center))
        Text(text = "kodedevel.ir", fontSize = 16.sp, modifier = Modifier.padding(16.dp).align(Alignment.BottomEnd))
    }
}
                

استفاده از Row و Column

Composable ها در Row به صورت افقی پشت سر هم قرار میگیرن و در Column به صورت عمودی؛ در تصویر زیر نحوه چیدمان Composable ها در Row و Column به صورت مستطیل های قرمز نمایش داده شده است.

نحوه چیدمان Composable ها در Row و Column
نحوه چیدمان Composable ها در Row و Column

چیدمان Composable ها در Row و Column بر مبنای محور مختصات است، Composable ها در Row در راستای محور X رسم میشن و در Column در راستای محور Y؛ به محور مختصاتی که همراستا با چیدمان ها باشه، محور مختصات اصلی میگیم.

توجه

در اندروید برخلاف محور مختصات در ریاضی جهت محور Y به سمت پایین است.

فرم کلی:

@Composable
fun Row(modifier: Modifier = Modifier, horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, verticalAlignment: Alignment.Vertical = Alignment.Top, content: RowScope.() -> Unit)

@Composable
fun Column(modifier: Modifier = Modifier, verticalArrangement: Arrangement.Vertical = Arrangement.Top, horizontalAlignment: Alignment.Horizontal = Alignment.Start, content: ColumnScope.() -> Unit)
                

با Modifier میتونیم لایه ها رو سفارشی‌سازی کنیم و با تعریف تابع لیترال برای content میتونیم Composable ها رو داخل تابع صدا بزنیم.

در مثال زیر میخوایم چند متن رو داخل Row و Column نمایش بدیم.

@Composable
fun MyTextsHorizontal(modifier: Modifier = Modifier){
    Row(modifier){
        Text(text = "First Text In Row"),
        Text(text = "Second Text In Row"),
        Text(text = "Third Text In Row"),
        Text(text = "Forth Text In Row")
    }
}

@Composable
fun MyTextsVertical(modifier: Modifier = Modifier){
    Column(modifier){
        Text(text = "First Text In Column")
        Text(text = "Second Text In Column")
        Text(text = "Third Text In Column")
    }
}
                

تعیین محل قرار گیری Composable ها

با استفاده از Arrangement و Alignment میتونیم محل قرارگیری چیدمان ها رو در Row و Column تعیین کنیم.

Arrangement

با استفاده از پارامتر Arrangement میتونیم محل قرارگیری Composable ها رو در راستای محوری که چیده میشن مشخص کنیم، در Row اسم این پارامتر horizontalArrangement است و در Column اسمش verticalArrangement.

در UML زیر مقادیر و توابع کلاس Arrangement شرح داده شده است.

Arrangement
Start مختص horizontalArrangement است و چیدمان رو در ابتدای محور اصلی X قرار میده.
End مختص horizontalArrangement است و چیدمان رو در انتهای محور اصلی X قرار میده.
Top مختص verticalArrangement است و چیدمان رو در ابتدای محور اصلی Y قرار میده.
Bottom مختص verticalArrangement است و چیدمان رو در انتهای محور اصلی Y قرار میده.
Center چیدمان ها رو در وسط محور مختصات اصلی قرار میده.
SpaceBetween فاصله روی محور اصلی فقط بین Composable ها تقسیم میشه.
SpaceEvenly فاصله ها (شامل قبل و بعد) کاملا یکسان است.
SpaceAround فاصله قبل از اولین Composable و بعد از آخرین Composable نصف فاصله بین Composable هاست.
spacedBy(space: Dp) یک فاصله ی دلخواه ایجاد میکنیم.

Alignment

با استفاده از پارامتر Alignment میتونیم محل قرارگیری Composable ها رو در راستای محور فرعی مختصات تعیین کنیم؛ در Row اسم این پارامتر verticalAlignment است و در Column اسم این پارامتر horizontalAlignment است.

برای verticalAlignment مقادیر Alignment.CenterVertically, Alignment.Topو Alignment.Bottom و برای horizontalAlignment مقادیر Alignment.CenterHorizontally, Alignment.Start و Alignment.End قابل استفاده است.

در جدول زیر مقادیر قابل استفاده برای هردو پارامتر verticalAlignment و horizontalAlignment شرح داده شده است.

verticalAlignment horizontalAlignment
Alignment.Top Alignment.Start
Alignment.CenterVertically Alignment.CenterHorizontally
Alignment.Bottom Alignment.End

یک تابع اکستنشن به نام align در Modifier برای ColumnScope و RowScope تعریف شده که با استفاده از تابع میتونیم محل قرار گیری هر Composable در محور فرعی رو به صورت جداگونه و اختصاصی تعریف کنیم.

@Composable
fun MyComposable(){
    Row{
        Text(text = "First Text In Row", modifier = Modifier.align(Alignment.Top))
        Text(text = "Second Text In Row", modifier = Modifier.align(Alignment.CenterVertically))
        Text(text = "Third Text In Row", modifier = Modifier.align(Alignment.Bottom))
    }

    Column{
        Text(text = "First Text In Column", modifier = Modifier.align(Alignment.Start))
        Text(text = "Second Text In Column", modifier = Modifier.align(Alignment.CenterHorizontally))
        Text(text = "Third Text In Column", modifier = Modifier.align(Alignment.End))
    }
}
                        

در مثال زیر میخوایم شیش متن رو به صورت عمودی و افقی بچینیم و نمایش بدیم.

@Composable
fun MyTexts(){

    Column(modifier = Modifier.padding(16.dp).fillMaxSize(), verticalArrangement = Arrangement.SpaceAround, horizontalAlignment = Alignment.CenterHorizontally) {
        Text("First Text in Column")
        Text("Second Text in Column")
        Text("Third Text in Column")
    }

    Row(modifier = Modifier.padding(16.dp).fillMaxSize(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.Bottom) {
        Text("First Text In Row")
        Text("Second Text In Row")
        Text("Third Text In Row")
    }
}

@Preview
@Composable
fun MyTextsPreview(){
    MyTexts()
}
                    

مورد مطالعه (مثال)

مثال های این بخش در آرایه ها در کاتلین اورده شده و در اینجا میخوایم به صورت UI در اندروید پیادشون کنیم.

در مثال زیر میخوایم یک ماتریکس رو در صفحه نمایش بدیم.

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Matrix(matrix, Modifier.padding(innerPadding))
                }
        }
    }
}

val matrix = arrayOf(
    arrayOf(10, 20, 30, 5),
    arrayOf(2, 3, 8 , 1),
    arrayOf(5, 7, 12, 21),
    arrayOf(14, 8, 16, 32)
)

@Composable
fun Matrix(matrix: Array>, modifier: Modifier){

    Box(modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Row(Modifier.border(1.dp, color = Color(0xFF212121))) {
            for (row in matrix.indices) {
                Column {
                    for (col in matrix[row].indices) {
                        val cell = matrix[row][col]
                        Text(
                            text = cell.toString(),
                            textAlign = TextAlign.Center,
                            fontSize = 24.sp,
                            modifier = Modifier.width(60.dp).border(1.dp, color = Color(0xFF212121)).padding(16.dp)
                        )
                    }
                }
            }
        }
    }
}

@Preview
@Composable
fun MatrixPreview(){
    Matrix(matrix, Modifier)
}
                

میخوایم یک برنامه بنویسیم که فاصله شهر ها رو نمایش بده.

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

//Qom, Hamadan, Tehran, Shiraz
private val arak = arrayOf(0, 132, 191, 282, 681)
//Arak, Hamedan, Tehran, Shiraz
private val qom = arrayOf(132, 0, 298, 149, 705)
//Arak, Qom, Tehran, Shiraz
private val hamadan = arrayOf(191, 298, 0, 318, 881)
//Arak, Qom, Hamedan, Shiraz
private val tehran = arrayOf(282, 149, 318, 0, 844)
//Arak, Qom, Hamedan, Tehran
private val shiraz = arrayOf(681, 705, 881, 844, 0)

val distances = arrayOf(arak, qom, hamadan, tehran, shiraz)

val cities = arrayOf("Arak", "Qom", "Hamadan", "Tehran", "Shiraz")
                

سپس از داده های تعریف شده در MainActivity استفاده می‌کنیم.

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                Box(modifier = Modifier
                    .padding(innerPadding)
                    .fillMaxSize()) {
                    CityDistances(Modifier.align(Alignment.Center))
                }
            }
        }
    }
}

@Composable
fun CityDistances(modifier: Modifier) {
    Column(modifier) {
        CitiesRow()
        Distances()
    }
}

@Preview
@Composable
fun CityDistancesPreview() {
    CityDistances(Modifier)
}

@Composable
fun CitiesRow(modifier: Modifier = Modifier) {
    Row(
        modifier
            .fillMaxWidth()
            .background(Color(0xFFF5F5F5)),
        horizontalArrangement = Arrangement.End
    ) {
        for (city in cities) {
            Text(
                text = city,
                textAlign = TextAlign.Center,
                fontWeight = FontWeight.Bold,
                modifier = Modifier.padding(8.dp)
            )
        }
    }
}

@Composable
fun CitiesColumn(modifier: Modifier = Modifier) {
    Column(modifier) {
        for (city in cities)
            Text(
                text = city,
                color = Color(0xFFFAFAFA),
                modifier = Modifier.padding(bottom = 16.dp, top = 16.dp),
                fontWeight = FontWeight.Bold
            )
    }
}

@Composable
fun Distances(modifier: Modifier = Modifier) {

    Row(
        modifier
            .fillMaxWidth()
            .background(Color(0xFF212121)),
        horizontalArrangement = Arrangement.End
    ) {
        CitiesColumn()
        for (row in distances.indices) {

            Column {
                for (col in distances[row].indices) {
                    val distance = distances[row][col]
                    Text(
                        text = distance.toString(),
                        color = Color(0xFFFAFAFA),
                        textAlign = TextAlign.Center,
                        modifier = Modifier.padding(16.dp)
                    )
                }
            }
        }
    }
}
                

تصویر نهایی باید مشابه زیر باشه.

برنامه فاصله شهر ها در اندروید کامپوز
برنامه فاصله شهر ها در اندروید کامپوز

خلاصه

  • Composable ها در Box به صورت استک روی هم قرار میگیرن.
  • Composable ها در Row به صورت افقی و در مسیر محور x پشت سر هم قرار میگیرن و در Column به صورت عمودی پشت سر هم و در مسیر محور Y.
  • به محور هم راستا در جهت قرار گرفتن Composable ها در Row و Column محور اصلی میگیم.
  • با استفاده از Arrangement در Row و Column میتونیم محل چیدمان Composable ها رو در محور اصلی تعیین کنیم.
  • با استفاده از Alignment در Row و Column میتونیم محل چیدمان Composable ها رو در محور دوم تعیین کنیم.

بازخورد و دیدگاه‌ ها

اولین نفری باشید که در این صفحه نظر می‌دهید

notifications برای اطلاع از جدیدترین مطالب و پست های مرتبط، عضو کانال تلگرام ما بشید.

arrow_drop_up
کپی شد!