لایه های کامپوزی (Composable Layouts)
در جتپک کامپوز میتونیم نحوه چیدمان Composable ها و محل قرارگیری چیدمان ها رو مشخص کنیم؛ برای این کار باید از لایه های کامپوزی (Composable Layouts) استفاده کنیم؛ لایه های کامپوزی میتونن یک یا چند Composable رو نگهدارن، هر لایه چیدمان خاص خودشو داره و میتونیم محل قرار گیری چیدمان Composable ها رو در لایه مشخص کنیم.
لایه های کامپوزی خودشون Composable هستن و میتونیم یک لایه کامپوزی رو به عنوان Composable به لایه کامپوزی دیگه اضافه کنیم.
سه تا از لایه های کامپوزی عبارتند از Box, Row و Column و این سه مبنا و اساس بسیاری از لایه های کامپوزی دیگه هستند.
استفاده از Box
Composable ها در لایه Box به صورت استک روی هم میوفتن، میتونیم Composable ها رو در 9 ناحیه مختلف در 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 در راستای محور 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 ها رو در محور دوم تعیین کنیم.
بازخورد و دیدگاه ها
اولین نفری باشید که در این صفحه نظر میدهید