توضیح @Composable — عنصر بنیادین Jetpack Compose است که یک تابع عادی Kotlin را به یک بلوک ساختاری اعلامی رابط کاربر تبدیل میکند. بدون این توضیح نمیتوان هیچ صفحهای را در توسعه اندروید مدرن ایجاد کرد. به گزارش Google Android Developers, 2026، بیش از 80% پروژههای جدید در Kotlin از Compose برای ساخت UI استفاده میکنند و @Composable پراستفادهترین توضیح در اکوسیستم است.
نکات کلیدی
@Composable — یک توضیح زبان Kotlin است که یک تابع را به عنوان مناسب برای توصیف رابط کاربر در چارچوب Jetpack Compose علامتگذاری میکند. وقتی کامپایلر Kotlin با این توضیح مواجه میشود، کد اضافهای تولید میکند که به تابع اجازه میدهد در زمینه ترکیب — سیستم مدیریت درخت UI کار کند.
توضیح @Composable توسط Google در سال 2021 همراه با اولین نسخه پایدار Jetpack Compose 1.0 معرفی شد. قبل از ظهور آن، توسعه رابطهای اندروید تنها از طریق نشانگذاری XML و سیستم View انجام میشد. @Composable رویکرد را به طور بنیادین تغییر داد: به جای توصیف UI در یک فایل نشانگذاری جداگانه، برنامهنویس رابط را مستقیماً در Kotlin مینویسد.
تفاوت اصلی @Composable با توابع عادی Kotlin — توانایی خواندن و واکنش به تغییرات وضعیت است. وقتی متغیری که تابع Composable آن را میخواند، مقدارش تغییر میکند، سیستم به طور خودکار اجرای مجدد (بازترکیب) آن تابع را برنامهریزی میکند. این برنامهنویس را از بهروزرسانی دستی UI از طریق findViewById و setText بینیاز میکند.
مکانیک داخلی @Composable بر مفهوم سلوت — یک منطقه حافظه ویژه که برای هر تابع در ترکیب اختصاص داده میشود استناد دارد. در این سلوت مقادیر ارسالشده به تابع و نیز اطلاعات خدماتی مورد نیاز برای مقایسه در فراخوانیهای بعدی ذخیره میشود.
برای اعلام یک تابع Composable، کافیست توضیح @Composable را قبل از کلمه کلیدی fun اضافه کنید. تابع باید در بستهای قرار داشته باشد که توضیح را از androidx.compose.runtime وارد کند. نام تابع توصیه میشود با حرف بزرگ نوشته شود — این یک قرارداد عمومی در جامعه Compose است که کامپوننتهای UI را از توابع عادی به صورت چشمی جدا میکند.
import androidx.compose.runtime.Composable
@Composable
fun Greeting(name: String) {
var count by remember { mutableStateOf(0) }
Column {
Text("سلام، $name!")
Button(onClick = { count++ }) {
Text("$count بار کلیک شد")
}
}
}
پارامترهای تابع Composable میتوانند هر چیزی باشند — انواع اولیه، رشتهها، لامبداها و حتی سایر توابع Composable که از طریق Slot API ارسال میشوند. توصیه میشود پارامترها را تغییرناپذیر (val) کنید تا از عوارض جانبی در بازترکیب جلوگیری شود. همه دادههای تغییرپذیر باید از طریق مکانیزمهای وضعیت Compose مدیریت شوند.
توابع Composable نمیتوانند مقدار دلخواهی را مانند توابع عادی بازگردانند — تنها وظیفه آنها ساخت یا بهروزرسانی قسمتی از درخت UI است. با این حال، الگوهای ویژهای مانند State Hoisting وجود دارد که در آن تابع Compose وضعیت و callbackها را از طریق پارامترها دریافت میکند و خالص و قابل استفاده مجدد باقی میماند.
سیستم Compose چندین محدودیت سختگیرانه بر شکل و رفتار توابع Composable اعمال میکند. قاعده اول: تابع Composable فقط میتواند سایر توابع Composable یا توابع عادی بدون عوارض جانبی را صدا بزند. این پیشبینی پذیری ترکیب و کارکرد صحیح بهینهسازیهای Compose را تضمین میکند.
قاعده دوم مربوط به ترتیب اجراست. Compose حق دارد توابع Composable را به هر ترتیبی صدا بزند، بنابراین کد در بدنه چنین تابعی نباید به تسلسل فراخوانی توابع مجاور اتکا کند. هر تابع Composable باید در سطح موقعیت خود در درخت UI خودکفا باشد.
قاعده سوم — ممنوعیت عوارض جانبی در خود بدنه تابع Composable. عملیاتی مانند نوشتن در پایگاه داده، ارسال درخواستهای شبکه یا تغییر متغیرهای خارجی باید تنها در داخل افکتهای ویژه LaunchedEffect، DisposableEffect یا SideEffect انجام شوند. نقض این قاعده منجر به رفتار غیرقابل پیشبینی در بازترکیبها میشود.
قاعده چهارم: توابع Composable باید همانگیر (ایدمپوتنت) باشند. فراخوانی مجدد با همان آرگومانها باید همان UI را تولید کند. این نیاز برای کارکرد صحیح بهینهسازی skipping ضروری است، که در آن Compose از تجدید ترسیم توابعی که دادههای ورودی آنها تغییر نکرده صرفنظر میکند.
// درست: تابع Composable خالص بدون عوارض جانبی
@Composable
fun UserCard(user: User, onClick: () -> Unit) {
Card(modifier = Modifier.clickable { onClick() }) {
Text(text = user.name)
}
}
// غلط: عارضه جانبی در داخل بدنه
@Composable
fun WrongCard(userId: String) {
// val result = viewModel.loadUser(userId) // مجاز نیست
Text("در حال بارگذاری...")
}
یک مثال عملی از ایجاد صفحه پروفایل با استفاده از توضیح @Composable را بررسی میکنیم. در اینجا ترکیب چندین تابع Composable، کار با وضعیت و مدیفایرها را نشان میدهیم — عناصر کلیدی هر چیدمان Compose.
@Composable
fun ProfileScreen(userId: String) {
var isFollowed by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
ProfileHeader(userId = userId)
Spacer(modifier = Modifier.height(16.dp))
StatsRow(posts = 42, followers = 1280)
Spacer(modifier = Modifier.height(24.dp))
FollowButton(
isFollowed = isFollowed,
onToggle = { isFollowed = !isFollowed }
)
}
}
@Composable
fun ProfileHeader(userId: String) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(model = "https://example.com/avatars/$userId",
contentDescription = "User avatar")
Spacer(modifier = Modifier.width(12.dp))
Text(text = "کاربر #$userId", style = MaterialTheme.typography.headlineMedium)
}
}
@Composable
fun StatsRow(posts: Int, followers: Int) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
StatItem("Posts", posts)
StatItem("Followers", followers)
}
}
@Composable
fun StatItem(label: String, value: Int) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "$value", style = MaterialTheme.typography.headlineSmall)
Text(text = label, style = MaterialTheme.typography.bodySmall)
}
}
در مثال، هر تابع Composable مسئول بخشی از صفحه است: ProfileScreen وضعیت کلی و ترکیب توابع فرعی را مدیریت میکند، ProfileHeader آواتار و نام را نمایش میدهد، و StatsRow — بلوک آمار. این رویکرد از اصل مسئولیت مفرد پیروی میکند و استفاده مجدد از کامپوننتها را سادهتر میکند.
در Jetpack Compose سه نوع اصلی از توابع Composable وجود دارد. نوع اول — ظروف (Row, Column, Box, LazyColumn) که جایگابی عناصر فرعی را تعیین میکنند. نوع دوم — عناصر نمایش (Text, Image, Icon, Button) که کامپوننتهای UI مشخصی را رندر میکنند. نوع سوم — توابع Composable سفارشی که کامپوننتهای ساختهشده را در بلوکهای قابل استفاده مجدد ترکیب میکنند.
ظروف از عناصر عادی با این تفاوت است که لامبدای content را — آخرین پارامتر از نوع @Composable () -> Unit را میپذیرند. دقیقاً این مکانیزم است که ایجاد درختهای UI تودرتو را ممکن میسازد: هر ظرف یک ترکیب فرعی با زمینه و حافظه خود ایجاد میکند.
توابع Composable سفارشی به دو زیرنوع تقسیم میشوند: هوشمند (smart) و ساده (dumb). توابع هوشمند وضعیت و منطق را مدیریت میکنند — شامل فراخوانیهای remember، LaunchedEffect و سایر APIهای Compose هستند. توابع ساده همه دادهها را از طریق پارامترها دریافت میکنند و تنها آنها را نمایش میدهند. تقسیم به کامپوننتهای هوشمند و ساده آزمونپذیری و استفاده مجدد از کد را بهبود میبخشد.
| نوع | مثال | کاربرد |
|---|---|---|
| ظرف | Column, Row, Box | مدیریت جایگابی عناصر فرعی |
| عنصر | Text, Image, Button | نمایش محتوا و پردازش ورودی |
| سفارشی | ProfileCard, UserList | ترکیب کامپوننتهای استاندارد |
مزیت اصلی توضیح @Composable — امکان ایجاد کامپوننتهای UI قابل استفاده مجدد بدون ارثبری و سلسله مراتب پیچیده کلاسهاست. بر خلاف سیستم View که هر عنصر سفارشی نیاز به ایجاد یک کلاس Java با سازندهها داشت، کامپوننت Composable صرفاً یک تابع Kotlin با پارامترهاست.
برای تامین استفاده مجدد، الگوی Slot API به کار میرود که در آن تابع Composable لامبداهای content را برای مناطق مختلف چیدمان خود دریافت میکند. به عنوان مثال، کامپوننت Card میتواند content جداگانهای برای عنوان، بدنه و بخش پایین دریافت کند که آن را برای هر صفحهای از برنامه جهانی میکند.
مدیفایرها (Modifier) نقش کلیدی در استفاده مجدد ایفا میکنند: آنها امکان تنظیم فاصلهها، اندازهها، کلیکها و آنیمیشنها را بدون تغییر خود کامپوننت فراهم میکنند. توصیه میشود همواره Modifier را به عنوان يک پارامتر با مقدار پیشفرض: Modifier = Modifier ارسال کنید — این رویه استانداردی است که در کتابخانههای رسمی Google پذیرفته شده.
@Composable
fun SectionCard(
modifier: Modifier = Modifier,
title: String,
content: @Composable () -> Unit
) {
Card(modifier = modifier) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = title, style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(8.dp))
content()
}
}
}
به لفط Slot API، کامپوننت SectionCard را میتوان در صفحات مختلف با محتوای متفاوت — فرمها، لیستها، بلوکهای متنی استفاده کرد. ترکیب مدیفایرها و Slot API کامپوننتهای Compose را بدون از دست دادن امنیت نوعی که Kotlin فراهم میکند، حداکثر انعطافپذیر میسازد.
سوالات متداول
@Composable تابع در زمینه ترکیب اجرا میشود و میتواند وضعیت را بخواند و به طور خودکار در صورت تغییر آن مجدداً اجرا شود. توابع عادی Kotlin به مکانیزمهای ردیابی وضعیت دسترسی ندارند و در ساخت درخت UI شرکت نمیکنند.
خیر، توابع Composable را فقط میتوان از سایر توابع Composable صدا زد، زیرا به زمینه ترکیب ویژهای نیاز دارد. برای ادغام کد Compose با Kotlin عادی، از روش setContent { } در Activity یا ComposeView در سیستم View استفاده میشود.
این یک قرارداد نامگذاری در جامعه Compose است. حرف بزرگ کامپوننتهای UI را از توابع عادی جدا میکند، پیرو از قواعد نامگذاری کلاسها. این یک الزام کامپایلر نیست، اما رویهای توصیهشده در مستندات Google است.
هیچ محدودیتی برای تعداد وجود ندارد. در عمل، یک صفحه بزرگ میتواند شامل 50–100 تابع Composable، از جمله کامپوننتهای ساختهشده (Text, Button) و سفارشی باشد. Compose درخت توابع را بهینه میکند و فقط توابعی را اجرا میکند که دادههای ورودی آنها تغییر کرده است.
معمولاً توابع Composable Unit بازمیگردانند، زیرا وظیفه آنها ساخت UI است. با این حال، توابع تخصصی مانند remember و derivedStateOf وجود دارند که با @Composable علامتگذاری شده و مقدار بازمیگردانند. این استثنا است، نه قاعده.
نتیجه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید