Column هو مكون Composable مدمج في Jetpack Compose من حزمة compose.foundation.layout الذي يرتب العناصر الفرعية عمودياً، واحداً تحت الآخر. Column هو المكافئ لـ LinearLayout مع اتجاه عمودي من نظام View القديم، ولكن على عكسه، يستخدم وصفاً تصريحياً ويتفاعل تلقائياً مع تغييرات الحالة. وفقاً لـ Google Android Developers, 2026، Column هو أحد الحاويات الأساسية الثلاث إلى جانب Row و Box.
النقاط الرئيسية
Column هي دالة Composable تقبل معلمات اختيارية: modifier و verticalArrangement و horizontalAlignment و content — وهي لامبدا مع ColumnScope. داخل Column، تُرتب دوال Composable الفرعية من الأعلى إلى الأسفل بترتيب الإعلان. ارتفاع Column يساوي مجموع ارتفاعات العناصر الفرعية بالإضافة إلى المساحة المحددة بواسطة Arrangement. العرض يساوي أقصى عرض للعنصر الفرعي مع مراعاة Alignment.
Column هي حاوية غير مرئية: ليس لها خلفية أو حدود افتراضية. إذا كنت بحاجة إلى خلفية، أضف Modifier.background() إلى Column نفسها. على عكس LazyColumn، تعرض Column جميع العناصر الفرعية في وقت واحد ولا تدعم الظاهرية. هذا يعني أن Column مناسبة فقط لمجموعات البيانات الصغيرة — حتى 10-15 عنصراً. للقوائم الطويلة، استخدم LazyColumn.
ColumnScope هو مستقبل لامبدا المحتوى لـ Column. يوفر معدّلات إضافية تعمل فقط داخل Column: weight() و align() و alignByBaseline(). هذه المعدّلات ليس لها معنى خارج Column لأنها تعتمد على خصائص الترتيب الرأسي. على سبيل المثال، Modifier.align(Alignment.CenterHorizontally) يحاذي العنصر الفرعي إلى مركز Column أفقياً.
VerticalArrangement يحدد كيفية توزيع المساحة الرأسية بين العناصر. القيم المتاحة: Arrangement.Top (افتراضي)، Bottom، Center، SpaceBetween، SpaceEvenly، SpaceAround. إذا كان ارتفاع Column أكبر من مجموع ارتفاعات العناصر، يوزع Arrangement المساحة الحرة. إذا كانت العناصر تشغل الارتفاع بالكامل، لا يكون لـ Arrangement تأثير.
HorizontalAlignment يحدد المحاذاة الأفقية لكل عنصر فرعي. Alignment.Start (افتراضي لـ LTR)، CenterHorizontally، End. يعمل Alignment على كل عنصر بشكل مستقل: إذا كان أحد العناصر ضيقاً وآخر عريضاً، فسيتم محاذاة الأول، وقد يمتد الثاني خارج حدود Column. يعمل Alignment فقط إذا كان لـ Column عرض ثابت أو fillMaxWidth.
Modifier لـ Column: تقبل Column معدّلاً (Modifier) يتم تطبيقه على الحاوية نفسها. Modifier.fillMaxWidth() و fillMaxHeight() و size() و padding() — جميع المعدّلات القياسية تعمل. ملاحظة خاصة: Modifier.height(IntrinsicSize.Min) يجبر Column على حساب الحد الأدنى للارتفاع بناءً على العناصر الفرعية باستخدام القياس Intrinsic.
@Composable
fun ColumnArrangementDemo() {
Column(
modifier = Modifier.fillMaxSize().background(Color(0xFFF5F5F5)),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("أعلى", modifier = Modifier.background(Color.Cyan))
Text("وسط", modifier = Modifier.background(Color.Magenta))
Text("أسفل", modifier = Modifier.background(Color.Yellow))
}
}
// IntrinsicSize: Column يضبط الارتفاع حسب المحتوى
@Composable
fun IntrinsicColumn() {
Column(
modifier = Modifier
.height(IntrinsicSize.Min)
.width(200.dp)
) {
Text("نص قصير")
Text("نص طويل جداً سيلتف داخل العمود")
}
}
| Arrangement | السلوك |
|---|---|
| Arrangement.Top | العناصر ملتصقة بالأعلى، المساحة الحرة في الأسفل |
| Arrangement.Center | العناصر في المنتصف، المساحة مقسمة بالتساوي أعلى وأسفل |
| Arrangement.SpaceBetween | العنصر الأول في الأعلى، الأخير في الأسفل، والباقي بالتساوي |
| Arrangement.SpaceEvenly | فجوات متساوية بين جميع العناصر والحواف |
| Arrangement.SpaceAround | فجوات متساوية بين العناصر، نصف فجوة عند الحواف |
Modifier.weight() هو معدّل ColumnScope يوزع المساحة الرأسية الحرة بين عناصر Column بشكل نسبي حسب الأوزان المحددة. إذا كان Column يشغل ارتفاع 400dp ومجموع ارتفاعات العناصر الفرعية 100dp، فسيتم تقسيم الـ 300dp المتبقية بين عناصر الوزن. عنصر بوزن (2f) سيحصل على ضعف مساحة عنصر بوزن (1f).
fill — المعامل الثاني للوزن: weight(weight: Float, fill: Boolean = true). إذا كان fill = true (افتراضي)، يتمدد العنصر ليشغل الارتفاع الكامل المتاح. إذا كان fill = false، يشغل العنصر ارتفاعه الجوهري فقط، وتبقى المساحة المتبقية فارغة. هذا مفيد عندما يجب أن يكون العنصر ملتصقاً بجانب واحد لكن الوزن يحدد فقط نسبة توزيع المساحة الفارغة.
قيود الوزن: يعمل الوزن فقط في Column بارتفاع ثابت أو fillMaxHeight(). إذا كان ارتفاع Column محدداً بالعناصر الفرعية (wrap content)، لا معنى للأوزان — فلا توجد مساحة حرة للتوزيع. أيضاً، لا يمكن دمج الوزن مع Modifier.height() على نفس العنصر — يتعارضان ويتم تجاهل الوزن.
@Composable
fun WeightedColumn() {
Column(
modifier = Modifier.fillMaxHeight().width(300.dp)
) {
// يأخذ 1/6 من الارتفاع (weight 1 من مجموع 1+2+3=6)
Box(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.background(Color.Red)
)
// يأخذ 2/6 من الارتفاع
Box(
modifier = Modifier
.weight(2f)
.fillMaxWidth()
.background(Color.Green)
)
// يأخذ 3/6 من الارتفاع
Box(
modifier = Modifier
.weight(3f)
.fillMaxWidth()
.background(Color.Blue)
)
}
}
Column يعرض جميع العناصر الفرعية فوراً. إذا كان هناك أكثر من 10-15 عنصراً، يخلق Column حملاً كبيراً على التركيب والقياس. LazyColumn، على النقيض، يعرض فقط العناصر المرئية ويعيد استخدام غير المرئية. للقوائم الطويلة، القوائم بآلاف العناصر، القوائم اللانهائية أو الدردشات — LazyColumn إلزامي.
متى يكون Column أفضل: شاشات النماذج (3-10 حقول)، بطاقات الملف الشخصي، الأعمدة الرأسية مع الأيقونات، القوائم. يدعم Column أيضاً IntrinsicSize، وهو مفيد للارتفاع التكيفي. بالإضافة إلى ذلك، Column أسهل في التصحيح — لا ظاهرية، جميع العناصر مرئية في Layout Inspector. لواجهة مستخدم ثابتة، Column هو الخيار الصحيح.
LazyColumn يوفر: تخزين العناصر مؤقتاً، الهوية المبنية على المفتاح، تحريك الإضافة/الإزالة (animateItemPlacement)، الرؤوس الثابتة (sticky headers). إذا كانت القائمة تحتوي على عناصر من أنواع مختلفة (viewType مختلفة)، استخدم LazyColumn مع sealed class في items. Column لا يدعم sticky headers (يجب محاكاتها عبر Column قابلة للتمرير). كما يدعم LazyColumn LazyVerticalGrid عند استخدام GridCells.
| المعيار | Column | LazyColumn |
|---|---|---|
| عدد العناصر | حتى 10-15 | أي عدد |
| الأداء | يعرض الكل دائماً | المرئية فقط + مخزن مؤقت |
| التمرير | عبر Modifier.verticalScroll | مدمج |
| IntrinsicSize | مدعوم | غير مدعوم |
| الرؤوس الثابتة | لا (محاكاة) | نعم (stickyHeader) |
| تحريك العناصر | غير مدمج | animateItemPlacement |
دعنا نلقي نظرة على شاشة ملف تعريف المستخدم حيث يُستخدم Column كحاوية رئيسية للصورة الرمزية والاسم والسيرة الذاتية وأزرار الإجراءات. هنا، Column مع IntrinsicSize.Min يتكيف مع المحتوى، ويُستخدم الوزن لتوزيع المساحة بين الأقسام.
@Composable
fun UserProfileCard(name: String, bio: String) {
Card(
modifier = Modifier.fillMaxWidth().padding(16.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(
modifier = Modifier.fillMaxWidth().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
// الصورة الرمزية
Icon(
imageVector = Icons.Default.AccountCircle,
contentDescription = "Avatar",
modifier = Modifier.size(64.dp)
)
// الاسم
Text(name, style = MaterialTheme.typography.headlineSmall)
// السيرة الذاتية
Text(bio, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 4.dp))
// أزرار الإجراءات
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.padding(top = 12.dp)
) {
Button(onClick = { }) { Text("رسالة") }
OutlinedButton(onClick = { }) { Text("متابعة") }
}
}
}
}
في المثال، يستخدم Column Arrangement.spacedBy(8.dp) لمسافات متساوية بين العناصر. horizontalAlignment = CenterHorizontally يحاذي الصورة الرمزية والاسم والسيرة الذاتية إلى المنتصف. Row داخل Column هي حاوية متداخلة للأزرار في صف واحد. هذا المزيج من Column (ترتيب رأسي) و Row (ترتيب أفقي) هو نمط بناء واجهة مستخدم نموذجي في Compose.
الأسئلة الشائعة
Column يعرض جميع العناصر الفرعية مرة واحدة، مما يتسبب في انخفاض FPS مع 100+ عنصر. LazyColumn يعرض فقط العناصر المرئية بالإضافة إلى مخزن مؤقت (عادة 3-5 شاشات). للشاشات الثابتة التي تحتوي على 3-10 عناصر، Column أسرع حيث لا يوجد عبء ظاهرية.
أضف Modifier.verticalScroll(rememberScrollState()) إلى Column. هذا يجعل Column قابلة للتمرير لكنه لا يوفر ظاهرية — لا تزال جميع العناصر تُعرض مرة واحدة. للقوائم الطويلة القابلة للتمرير، استخدم LazyColumn.
نعم، التداخل بين Row/Column ممارسة شائعة. من خلال الجمع بين الحاويتين، يمكن بناء شبكات معقدة. ومع ذلك، تجنب التداخل العميق (4+ مستويات) دون ضرورة — فهو يزيد من عدد قياسات LayoutNode ويبطئ التركيب.
استخدم Modifier.fillMaxWidth() على كل عنصر فرعي. إذا كان Column لديه Modifier.fillMaxWidth()، فجميع العناصر الفرعية التي تستخدم fillMaxWidth() ستمتد للعرض الكامل. بديل: استخدم Modifier.weight(1f) في ColumnScope إذا كان Column داخل حاوية ثابتة.
Arrangement.spacedBy(space) يضيف فجوة ثابتة بين كل عنصرين متجاورين. على عكس SpaceBetween/SpaceAround، لا يمتد spacedBy العناصر — الفجوة ثابتة، والمساحة المتبقية تبقى في نهاية Column. spacedBy لا يضيف فجوة قبل العنصر الأول ولا بعد العنصر الأخير.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا