Composable Function: ما هي، بناء جملة الدالة والقواعد

المؤلف: IT Sectr نُشر: 2026-06-27 وقت القراءة: 8 دق

Composable Function هي وحدة أساسية لواجهة المستخدم في Jetpack Compose تحدد كيف يجب أن يبدو ويتصرف جزء من الشاشة. كل دالة من هذه الدوال موسومة بالتعليق @Composable وتنفذ في سياق خاص يسمح لـ Compose بتتبع التبعيات وإعادة بناء واجهة المستخدم تلقائياً عند تغير البيانات. وفقاً لـ Google Android Developers, 2026، فإن البناء الصحيح لدوال Composable يؤثر مباشرة على أداء التطبيق وكفاءة إعادة التركيب.

الخلاصة

  • Composable Function — دالة Kotlin مع التعليق @Composable تبني شجرة واجهة المستخدم
  • المعاملات يجب أن تكون غير قابلة للتغيير، والبيانات المتغيرة تمر عبر الحالة
  • الاستدعاء ممكن فقط من سياق دالة Composable أخرى
  • ترتيب التنفيذ غير مضمون — يجب أن تكون كل دالة مستقلة
  • Modifier يوصى بتمريره كمعامل للتخصيص

ما هي Composable Function في Jetpack Compose

Composable Function هي دالة في لغة Kotlin، موسومة بالتعليق @Composable، تصف جزءاً من واجهة المستخدم بطريقة تصريحية. بدلاً من إنشاء وتكوين كائنات View عبر كود Java أو ترميز XML، يكتب المطور ببساطة كيف يجب أن تبدو واجهة المستخدم لكل حالة من حالات البيانات.

الفرق الرئيسي بين دالة Composable ونظام View التقليدي في Android يكمن في نموذج التحديث. في النهج الكلاسيكي، كان المطور يستدعي findViewById يدوياً، ويغير النص عبر setText، ويدير الرؤية عبر setVisibility. Composable Function تحررك من هذه الروتين: عندما تتغير البيانات، يحدد النظام نفسه أي الدوال تحتاج إلى إعادة التركيب وينفذها فقط.

مترجم Kotlin، عند معالجة التعليق @Composable، يولد كوداً إضافياً يدمج الدالة في آلية التركيب. يتضمن هذا الكود القراءة والكتابة في slots — خلايا ذاكرة خاصة تخزن الحالة والمعاملات لكل دالة Composable في شجرة واجهة المستخدم الحالية. بفضل هذا التكامل، يعرف Compose أي الدوال تعتمد على أي بيانات.

بناء جملة تعريف دالة Composable

بناء جملة دالة Composable موجز للغاية: basta بإضافة @Composable قبل الكلمة المفتاحية fun. يمكن للدالة قبول أي معاملات، وتضمين استدعاءات Composable أخرى في جسمها، واستخدام تركيبات Kotlin — الشروط، الحلقات، تعبيرات when — للعرض الشرطي لواجهة المستخدم.

kotlin
@Composable
fun ProductItem(
    product: Product,
    modifier: Modifier = Modifier,
    onAddToCart: () -> Unit
) {
    Card(modifier = modifier.padding(8.dp)) {
        Row(modifier = Modifier.fillMaxWidth().padding(12.dp),
            verticalAlignment = Alignment.CenterVertically) {
            Column(modifier = Modifier.weight(1f)) {
                Text(text = product.name, style = MaterialTheme.typography.titleMedium)
                Text(text = "${product.price}", color = MaterialTheme.colorScheme.primary)
            }
            Button(onClick = onAddToCart) {
                Text("أضف إلى السلة")
            }
        }
    }
}

في هذا المثال، دالة Composable ProductItem تقبل كائن Product ومعدلاً وcallback. جميع المعاملات الثلاثة غير قابلة للتغيير، مما يضمن سلوكاً يمكن التنبؤ به أثناء إعادة التركيب. يتم تمرير المعدل كمعامل بقيمة افتراضية — هذه ممارسة قياسية تسمح للمستدعي بتخصيص الهوامش والأحجام.

المكونات والمعدلات في دوال Composable

داخل دالة Composable، تُستخدم مكونات Material Design المدمجة (Text, Button, Card, TextField) أو البدائيات الأساسية (Canvas, Layout). كل مكون يقبل معاملات لتكوين المظهر والسلوك، بالإضافة إلى معدل واحد أو أكثر عبر معامل modifier.

المعدلات هي سلسلة من الدوال التي تغير الحجم والموضع ومعالجة الأحداث ومظهر المكون. ترتيب المعدلات في السلسلة مهم: clickable.semantics يعمل بشكل مختلف عن semantics.clickable، و padding.background يلون المساحة والخلفية بما في ذلك padding، وهو أمر بالغ الأهمية عند التصميم.

داخل دالة Composable، يمكنك استخدام شروط if و when للعرض الشرطي لأجزاء واجهة المستخدم، بالإضافة إلى حلقات for للقوائم الديناميكية. كل هذه التركيبات تعمل بشكل طبيعي لأن Kotlin هي لغة برمجة كاملة. ومع ذلك، من المهم التذكر: إذا كان الشرط أو الحلقة يحتوي على استدعاءات لدوال Composable، فإنها تشارك أيضاً في إعادة التركيب.

kotlin
@Composable
fun ProductList(
    products: List<Product>,
    modifier: Modifier = Modifier
) {
    LazyColumn(modifier = modifier) {
        items(products, key = { it.id }) { product ->
            ProductItem(
                product = product,
                onAddToCart = { /* add to cart */ }
            )
        }
    }
}

أمثلة على دوال Composable لشاشات حقيقية

لنفكر في مثال لشاشة بحث عن منتجات باستخدام عدة دوال Composable. هنا تظهر أنماط نموذجية: حقل إدخال مع حالة، تصفية قائمة، معالجة النتائج الفارغة والتحميل.

kotlin
data class Product(
    val id: String,
    val name: String,
    val price: Double,
    val category: String
)

@Composable
fun SearchScreen() {
    var query by remember { mutableStateOf("") }
    val products = remember(query) { getFilteredProducts(query) }

    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        OutlinedTextField(
            value = query,
            onValueChange = { query = it },
            label = { Text("البحث عن المنتجات") },
            modifier = Modifier.fillMaxWidth()
        )

        Spacer(modifier = Modifier.height(16.dp))

        when (products) {
            is Loading -> CircularProgressIndicator()
            is Empty -> Text("لم يتم العثور على نتائج")
            is Result -> LazyColumn {
                items(products.items, key = { it.id }) { product ->
                    ProductItem(product = product, onAddToCart = {})
                }
            }
        }
    }
}

هذا المثال يوضح عدة أساليب في وقت واحد: remember للحفاظ على حالة استعلام البحث، remember(query) للتصفية بمفتاح، when لثلاث حالات لواجهة المستخدم و LazyColumn لعرض القائمة بكفاءة. كل من هذه الأساليب هي نتيجة خبرة عملية في تطوير تطبيقات Compose.

المعاملات و Slot API

دوال Composable تقبل المعاملات تماماً مثل دوال Kotlin العادية، ولكن مع فرق مهم: يمكن أن يكون المعامل دالة Composable أخرى يتم تمريرها عبر lambda مع التعليق @Composable. هذه الآلية تسمى Slot API وهي النمط الرئيسي لإنشاء حاويات قابلة لإعادة الاستخدام.

Slot API يحل المشكلة التي كانت في نظام View التقليدي تُحل عبر ViewGroup وإضافة Views فرعية برمجياً. بدلاً من طرق addView، يستخدم Compose lambdas content — المعامل الأخير بنوع @Composable () -> Unit. يقوم المستدعي بتمرير أي واجهة مستخدم داخل هذه lambda، والحاوية تحدد فقط تخطيطها.

يمكن أن تحتوي معاملات دوال Composable على قيم افتراضية، مما يبسط استخدامها في سياقات مختلفة. يوصى بجعل إلزامية فقط تلك المعاملات التي بدونها لا تستطيع الدالة أداء مهمتها، وتزويد الباقي بقيم افتراضية معقولة.

المعاملالنوعمثال
إلزاميأي نوعname: String
اختياريبقيمة افتراضيةmodifier: Modifier = Modifier
Content@Composable () -> Unitcontent: @Composable () -> Unit
CallbackLambda بدون @ComposableonClick: () -> Unit

أساليب دوال Composable في Kotlin

ظهرت في مجتمع Compose العديد من الأساليب الراسخة التي تجعل دوال Composable أكثر قابلية للقراءة وقابلية للتنبؤ. الأول هو State Hoisting: يتم رفع الحالة إلى مستوى أعلى، وتستقبلها دالة Composable عبر المعاملات. هذا يجعل الدالة نقية وقابلة لإعادة الاستخدام في سياقات مختلفة.

الأسلوب الثاني هو معاملات Event-driven. بدلاً من تمرير ViewModel أو useCase إلى دالة Composable، يتم تمرير callbacks محددة فقط: onSave, onDelete, onNavigateToDetail. هذا يقلل الاقتران ويبسط الاختبار — اختبار ProductItem لا يحتاج ViewModel، فقط lambda وهمية.

الأسلوب الثالث هو CompositionLocal لتمرير البيانات المشتركة عبر شجرة التركيب. السمة، كثافة الشاشة، المسار الحالي — كل هذا يمر عبر CompositionLocal، متجنباً سلاسل المعاملات عبر عشرات دوال Composable. ومع ذلك، لا ينبغي الإفراط في استخدام CompositionLocal: المعاملات الصريحة دائماً أفضل من التبعيات الضمنية.

kotlin
// State Hoisting: تم رفع الحالة إلى الدالة الأم
@Composable
fun CounterDisplay(
    count: Int,
    onIncrement: () -> Unit
) {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "العداد: $count", style = MaterialTheme.typography.headlineLarge)
        Button(onClick = onIncrement) {
            Text("+1")
        }
    }
}

// الاستخدام مع State Hoisting
@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }
    CounterDisplay(
        count = count,
        onIncrement = { count++ }
    )
}

الأسئلة الشائعة

هل يمكن استخدام return في دالة Composable؟

نعم، return مسموح به، ولكن بحذر. Compose يحسن إعادة التركيب على مستوى الدوال الفردية، و return المبكر قد يكسر هذا التحسين. من الأفضل استخدام العوامل الشرطية if أو when داخل جسم الدالة.

كيف يختلف Unit-return عن void في Java؟

في Kotlin، Unit هو كائن singleton، وليس نوعاً فارغاً. دوال Composable ترجع Unit، مما يعني تقنياً أنها ترجع كائن Unit نفسه. ومع ذلك، في الممارسة العملية لا يهم هذا — قيمة الإرجاع يتم تجاهلها من قبل نظام التركيب.

هل يمكن تمرير mutableListOf إلى دالة Composable؟

تمرير المجموعات القابلة للتغيير ممكن، لكنها ممارسة سيئة. إذا تغيرت المجموعة، لن يعرف Compose بذلك لأن مرجع الكائن بقي كما هو. استخدم قوائم غير قابلة للتغيير أو mutableStateListOf للتغييرات المتتبعة.

كيف يمكن تصحيح أخطاء دالة Composable؟

لتصحيح الأخطاء، استخدم Android Studio مع Layout Inspector، الذي يظهر شجرة دوال Composable الحالية، قيم المعاملات وأسباب إعادة التركيب. مصحح أخطاء Kotlin العادي يعمل أيضاً — نقاط التوقف داخل دوال Composable يتم تفعيلها بشكل صحيح في كل إعادة تركيب.

هل من الإلزامي تحديد نوع الإرجاع لدالة Composable؟

دالة Composable ترجع دائماً Unit، لذلك لا يتم تحديد نوع الإرجاع. محاولة إرجاع نوع آخر ستسبب خطأ في الترجمة لأن التعليق @Composable غير متوافق مع أنواع الإرجاع غير Unit.

الملخص

  • Composable Function — لبنة بناء تصريحية لواجهة المستخدم موسومة بـ @Composable
  • المعاملات يجب أن تكون غير قابلة للتغيير لإعادة تركيب يمكن التنبؤ به
  • المعدلات و Slot API توفر المرونة وإعادة الاستخدام دون وراثة
  • State Hoisting — رفع الحالة للأعلى للنظافة وقابلية الاختبار
  • Callbacks Event-driven تقلل الاقتران مع ViewModel ومنطق الأعمال
  • CompositionLocal يستخدم للبيانات المشتركة، لكن المعاملات الصريحة أفضل
  • أساليب Compose تجعل الكود قابلاً للتنبؤ والاختبار والفعالية

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا