نشرح أساسيات LinearLayout — ViewGroup أساسية في Android SDK لمحاذاة العناصر الفرعية في سطر واحد: عمودياً (LinearLayout.VERTICAL) أو أفقياً (LinearLayout.HORIZONTAL). يظل LinearLayout أبسط وأسرع طريقة لبناء صف من الأزرار أو قائمة إعدادات أو نموذج إدخال عندما لا يتجاوز تعقيد التخطيط 5–10 عناصر. تدير السمات layout_weight و orientation توزيع المساحة والاتجاه. المواصفات التفصيلية — في LinearLayout API Reference.
النقاط الرئيسية
LinearLayout — واحدة من أولى ViewGroups في Android SDK (API Level 1)، مصممة لوضع العناصر الفرعية بشكل متسلسل في صف أو عمود واحد. يتم وضع كل عنصر جديد بعد العنصر السابق، ويتم تعيين الاتجاه بواسطة السمة android:orientation. LinearLayout هو أبسط وأكثر حاويات Android توقعاً، مما يجعله الخيار المثالي للواجهات الخطية: صفوف الأزرار، قوائم الإعدادات مع أيقونة ونص، قوائم أفقية.
تاريخياً، LinearLayout هو أول ViewGroup يتعرف عليها مطور Android المبتدئ. ميزته هي الشفافية: يتم وضع العناصر الفرعية بدقة حسب ترتيب الإعلان، دون قواعد تحديد موضع مخفية. على عكس RelativeLayout، حيث يمكن ربط العنصر بأي جار، أو ConstraintLayout مع نظام القيود الخاص به، يعمل LinearLayout وفق مبدأ "الأول يسار/أعلى، الثاني بعده، الثالث بعد الثاني". وفقاً لـ Google I/O 2017، 78% من الشاشات في أفضل 1000 تطبيق في Google Play تستخدم LinearLayout كحاوية رئيسية أو مساعدة.
المقياس الرئيسي لـ LinearLayout هو LinearLayout.MeasureSpec — نظام إدارة الحجم. مع الاتجاه VERTICAL، عرض كل عنصر يساوي عرض الأب (match_parent أو ثابت)، ويتم تحديد الارتفاع حسب المحتوى أو السمة. بالنسبة لـ HORIZONTAL، العكس: الارتفاع يساوي الأب، العرض حسب المحتوى. إذا تجاوز العرض الإجمالي للعناصر في صف HORIZONTAL عرض الأب، فقد تفيض العناصر خارج الشاشة (إذا لم يتم استخدام weight).
يتجاوز LinearLayout كلاً من onMeasure و onLayout من ViewGroup. مع الاتجاه VERTICAL، يضع onLayout العناصر على طول المحور Y: الطفل الأول — y=0، الثاني — y=prev.bottom + divider.hidden، وهكذا. مع HORIZONTAL — على طول المحور X. يتم تعيين الفاصل عبر android:divider و android:showDividers (beginning, middle, end). يمكن أن يكون الفاصل لوناً أو drawable أو مورد Shape مخصصاً.
الاتجاه — سمة رئيسية لـ LinearLayout تحدد اتجاه وضع العناصر الفرعية. android:orientation="vertical" يرتب العناصر من الأعلى إلى الأسفل؛ android:orientation="horizontal" — من اليسار إلى اليمين (أو من اليمين إلى اليسار مع التوطين RTL). إذا لم يتم تعيين الاتجاه، يتم استخدام HORIZONTAL افتراضياً (في الإصدارات القديمة) — لكن التحديد الصريح ضروري لسلوك يمكن التنبؤ به.
android:gravity — يضبط المحتوى داخل LinearLayout. يقبل المجموعات: top, bottom, left, right, center, center_horizontal, center_vertical, fill, clip_vertical, clip_horizontal. قيمة gravity="center" لتخطيط VERTICAL ستوسط جميع العناصر أفقياً. android:layout_gravity — سمة العنصر الفرعي التي تضبطه داخل LinearLayout الأب. مثال: زر مع layout_gravity="right" في تخطيط VERTICAL سيدفع الزر إلى الحافة اليمنى.
الفرق: gravity — خاصية الأب (كيف يتم ترتيب الأطفال داخله)، layout_gravity — خاصية الطفل (كيف يتصرف داخل الأب). الخلط بين هذه السمات هو أحد أكثر الأخطاء شيوعاً بين المبتدئين.
لتخطيطات HORIZONTAL مع عناصر نصية (TextView, Button, EditText)، android:baselineAligned="true" مفيد — فهو يضبط كل النصوص حسب خط الأساس للخط، بغض النظر عن padding أو الحجم أو الارتفاع. هذا يجعل الصف مع أيقونة وعنوان ووصف مرتباً بصرياً: النص لا يقفز لأعلى ولأسفل.
layout_weight — سمة العنصر الفرعي لـ LinearLayout تحدد أي جزء من المساحة الحرة سيشغله. يعمل فقط في اتجاه الاتجاه (العرض لـ HORIZONTAL، الارتفاع لـ VERTICAL). صيغة الحساب: الحجم = الحجم الخاص + (المساحة الحرة × (وزن العنصر / مجموع كل الأوزان)). المساحة الحرة = حجم الأب — مجموع كل الأحجام الخاصة للأطفال.
layout_weight أكثر كفاءة من الأحجام الثابتة للواجهات التكيفية. على سبيل المثال، إذا كان يجب أن تشغل اللوحة اليسرى 30% من الشاشة واليمنى 70%، قم بتعيين weight=3 و weight=7. للتشغيل الصحيح، عادةً ما يتم تعيين الحجم في الاتجاه إلى 0dp (android:layout_width="0dp" لـ HORIZONTAL)، ثم يعتبر الحجم الخاص للعنصر صفراً، ويتم تحديد الحجم بالكامل فقط بواسطة weight. هذا هو التوصية القياسية من Google (Android Developers Guide, 2024).
مهم: يتم جمع الأوزان لجميع العناصر في LinearLayout، بما في ذلك تلك التي ليس لها weight محدد (وزنها يعتبر 0). إذا كان وزن عنصر weight=1 وآخر weight=2، فسيشغل الأول 1/3 من المساحة الحرة، والثاني — 2/3. weightSum (سمة الأب) تسمح بتعيين الحد الأقصى لمجموع الوزن — إذا كان مجموع أوزان الأطفال أقل من weightSum، يبقى الفرق كمساحة فارغة.
يتكون نموذج تسجيل الدخول من ثلاثة عناصر: حقل البريد الإلكتروني (يشغل 2/4)، حقل كلمة المرور (1/4) وزر (1/4) من ارتفاع الشاشة. تعمل العناصر الثلاثة مع weight فقط في الاتجاه VERTICAL حسب الارتفاع.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:hint="Email" />
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:hint="كلمة المرور"
android:inputType="textPassword" />
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="تسجيل الدخول" />
</LinearLayout>
ارتفاع كل عنصر = (parent_height — padding) × (weight / sumWeights). email يحصل على 2/4 من الارتفاع، كلمة المرور والزر — 1/4 لكل منهما. جميع height=0dp، لذلك لا يتم أخذ الحجم الخاص في الاعتبار — فقط weight يعمل.
لوحة بثلاثة أزرار: أيقونة الرجوع (wrap_content)، العنوان (ملء المتبقي) وأيقونة القائمة (wrap_content). weight للعنوان = 1، الأزرار بدون weight.
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical">
<ImageButton
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_back" />
<TextView
android:id="@+id/toolbar_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="العنوان"
android:textSize="18sp" />
<ImageButton
android:id="@+id/btn_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_more_vert" />
</LinearLayout>
تأخذ أزرار الرجوع والقائمة مساحة تساوي بالضبط ما هو مطلوب للأيقونة. العنوان (TextView) مع width=0dp و weight=1 يتمدد ليشغل كل المساحة المتبقية بينهما. gravity="center_vertical" يضبط جميع العناصر في المنتصف عمودياً.
بطاقة منتج: صف أفقي (صورة + كتلة نص عمودية). LinearLayout الخارجي HORIZONTAL، الداخلي — VERTICAL للعنوان والوصف والسعر.
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/product_image"
android:scaleType="centerCrop" />
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="12dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="اسم المنتج"
android:textStyle="bold"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="وصف مختصر للمنتج في سطرين"
android:textSize="14sp"
android:textColor="@color/gray" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1,299 RUB"
android:textSize="18sp"
android:textColor="@color/accent" />
</LinearLayout>
</LinearLayout>
الصورة على اليسار (80×80dp)، على اليمين — كتلة عمودية من ثلاثة أسطر نصية. LinearLayout الداخلي لديه weight=1، لذلك يشغل كل المساحة المتبقية بعد الصورة. هذا نمط كلاسيكي لبطاقة القائمة يوجد في آلاف التطبيقات.
العيب الرئيسي لـ LinearLayout — الحاجة إلى حاويات متداخلة للتخطيطات المعقدة. إذا كنت بحاجة إلى ترتيب عناصر في شبكة 2×2 أو إنشاء صف بمحاذاة على كلا الحافتين، فستحتاج إلى 2–3 مستويات من التداخل على الأقل. كل مستوى LinearLayout يضيف 2 تمريرتين من onMeasure، مما يؤدي على الأجهزة الضعيفة إلى تباطؤ ملحوظ أثناء العرض.
وفقاً لـ Android Performance Blog (Google, 2017)، كل مستوى إضافي من التداخل يزيد وقت التخطيط بمقدار 30–50 ميكروثانية. لقائمة من 20 عنصراً مع 3 مستويات من التداخل، يمكن أن يصل التأخير إلى 3 مللي ثانية لكل عنصر — وهذا jank ملحوظ أثناء التمرير. يحل ConstraintLayout هذه المشكلة من خلال تسلسل هرمي مسطح، ليحل محل 3–4 LinearLayouts متداخلة بحاوية قيود واحدة.
توصية: استخدم LinearLayout للتخطيطات الخطية البسيطة (حتى 10 عناصر، مستوى تداخل واحد). لبطاقات القوائم والنماذج بمحاذاة مختلفة والشاشات ذات هيكل الجدول، اختر ConstraintLayout. للعناصر المتكررة في RecyclerView، استخدم ConstraintLayout في ملف تخطيط العنصر — هذا أمر بالغ الأهمية لأداء التمرير.
الأسئلة الشائعة
السبب الأكثر شيوعاً — لم يتم تعيين الحجم في الاتجاه إلى 0dp. لتخطيط HORIZONTAL تحتاج android:layout_width="0dp"، لـ VERTICAL — android:layout_height="0dp". إذا كان للعنصر wrap_content أو match_parent، فقد لا يعمل weight أو يعطي نتائج غير متوقعة. السبب الثاني — weightSum على الأب أقل من مجموع أوزان الأطفال. السبب الثالث — استخدام match_parent على عنصر فرعي في الاتجاه المعاكس.
layout_weight يتم تعيينه على كل عنصر فرعي ويحدد حصته من المساحة الحرة. weightSum — سمة الأب LinearLayout التي تعين الحد الأقصى لمجموع الأوزان. افتراضياً، weightSum = مجموع كل layout_weight للأطفال. إذا قمت بتعيين weightSum = 3، والأطفال لديهم weight=1، فسيشغل كل منهم 1/3. إذا كان هناك طفلان فقط مع weight=1، فإن 1/3 المتبقي سيكون فارغاً. weightSum مناسب لتثبيت النسب دون إعادة حساب عند إضافة/إزالة العناصر.
افتراضياً لا توجد مسافات — يتم وضع العناصر متجاورة. إذا ظهرت مسافات، تحقق من: android:divider و android:showDividers على الأب، android:layout_margin على العناصر الفرعية. بالإضافة إلى ذلك، قد يؤثر android:weightSum — إذا كانت العناصر تستخدم weight، فقد تبقى مساحة فارغة بينها بسبب حساب غير صحيح. لإزالة المسافات تماماً، اضبط جميع هوامش العناصر الفرعية على 0dp وأزل الفاصل.
للتخطيطات البسيطة أحادية الاتجاه (1–5 عناصر في صف/عمود) LinearLayout أسرع قليلاً — لا يستهلك موارد في حساب القيود. للتخطيطات المعقدة (أكثر من 5 عناصر، شبكات، أنواع مختلفة من المحاذاة) ConstraintLayout أسرع لأنه يستخدم تسلسلاً هرمياً مسطحاً بدلاً من LinearLayouts متداخلة. وفقاً لاختبارات Google (Android Performance Blog)، يربح ConstraintLayout في التخطيطات التي تتطلب 3+ مستويات من تداخل LinearLayout.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.