- بادئ الموضوع
- المشرف
- #1
مقدّمة
يتوفَّر في حزمة تطوير تطبيقات آندرويد (Android SDK) عدّة نماذج (Layouts) يمكن احتواء عناصر الواجهة فيها، وكلّ نموذج من هذه النماذج يقوم بترتيب العناصر التي يحتويها بطريقة مختلفة، فمثلاً نموذج LinearLayout يقوم بترتيب العناصر إمّا عموديّاً (Vertically) بحيث يكون كل عُنصر أسفل العُنصر الذي يسبقه، أو أفقيّاً (Horizontally)، بحيث توضع العناصر بجانب بعضها البعض. لذلك، فإنَّ طريقة محاذاة العناصر تختلف من نموذج لآخر، وسنقوم في هذا المقال باستعراض الطريقة المناسبة لكل نموذج من النماذج الأكثر استخداماً، وهي: ConstraintLayout، وRelativeLayout، وLinearLayout، وFrameLayout.
ConstraintLayout
يعتمد نموذج ConstraintLayout، وهو النموذج الذي يتمّ تحديده بشكلٍ تلقائيّ في Android Studio عند إنشاء مشروعاً جديداً، على شروط (Constraints) يتم تحديدها لكلّ عُنصر، ومن هذه الشروط ما هو مُتعلِّق بالعُنصُر نفسه، ومنها ما يُحدِّد علاقة العُنصُر بغيره من العناصر.
عند إضافة عُنصُراً جديداً في هذا النموذج، سيتم وضعه بشكلٍ تلقائيّ في أعلى يسار النموذج كما يلي:
لنقلّ العُنصُر إلى الوسط، يجب علينا تحديد أربعة شروط بين العُنصُر والLayout التي تحتويه، والذي يُعتَبَر عُنصره الأمّ (Parent). لتحديد شروط عُنصُر في ConstraintLayout، نقوم بالنقر على العُنصُر، ومن ثمَّ فرز قائمة Constraints كما هو مبيَّن أدناه:
بعد ذلك، نقوم بتحديد الخواصّ التالية: bottom_toTopOf، وtop_toBottomOf، وleft_toRightOf، وright_toLeftOf، بحيث نختار في كلّ منها علاقتها بالعُنصُر الأمّ وهو parent. بذلك سينتقل العنصر إلى الوسط:
ما يلي هو الكود النهائي الخاصّ بالواجهة:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="barmej.com"
android:textColor="@android:color/holo_red_dark"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>
في حال أردنا إضافة عُنصُر آخر أيضاً في الوسط، فنقوم بإجراء نفس الخطوات، ولكن نُغيِّر أحد الشروط الأربعة (أو غيرها ممّا يُمثِّل علاقة العنصر بغيره) بحسب العلاقة التي نريدها مع العُنصُر المتواجد مُسبقاً.
فمثلاً لو أردنا إضافة عُنصُر جديد أسفل جملة “barmej.com”، فسنقوم بتحديد شرط top_toBottomOf للعنصر الجديد ونقوم باختيار عُنصُر جملة “barmej.com”، ولا داعي لتحديد شرط bottom_toTopOf في هذه الحالة، لأنَّ تحديد علاقة العنصر الجديد بالعُنصُر الأصلي كافية لإعلام نظام آندرويد بمكان العنصر الجديد:
ما يلي هو الكود النهائي بعد إضافة العنصر الجديد:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="barmej.com"
android:textColor="@android:color/holo_red_dark"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="الموقع الأفضل لتعلم البرمجة!"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
</android.support.constraint.ConstraintLayout>
RelativeLayout
يشبه مبدأ عمل نموذج RelativeLayout إلى حدّ كبير مبدأ عمل نموذج ConstraintLayout، ولكن باستثناء اختلاف وحيد، وهو أنّه في نموذج RelativeLayout يتم تحديد علاقة كُل عنصر بالعناصر التي حوله دون تحديد أيّة شروط للعنصر ذاته.
يوفِّر نموذج RelativeLayout خاصيّتين يمكننا استخدامهنّ لمحاذاة العناصر للوسط، وهما: layout_centerHorizontal، وlayout_centerVertical. الأولى هي لمحاذاة العنصر للوسط أفقيّاً، أمّا الأخيرة فللحالة العموديّة، كما توجد خاصيّة layout_centerInParent، والتي بتفعيلها يتم نقل العنصر إلى وسط النموذج تلقائيّاً دون الحاجة لتفعيل أيّ خيارات أخرى.
وبذلك نتمكَّن من محاذاة العنصر إلى الوسط:
وما يلي هو الكود الخاصّ بالواجهة أعلاه:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="مرحبا بك!"
android:textSize="30sp"
android:textStyle="bold" />
</RelativeLayout>
LinearLayout
يمكن للعناصر الموجودة في نماذج LinearLayout الاستفادة من خاصيّة layout_gravity، إذ من خلال هذه الخاصيّة يمكن تحديد الجهة التي يُفضِّل العنصر الانحياز لها في النموذج الذي يحتويه:
ما يلي مثال على استخدام خاصيّة layout_gravity لمحاذاة 5 عناصر من نوع TextView إلى الوسط:
الكود الخاصّ بالواجهة:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
androidrientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="مرحبا بك"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="في موقع"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="برمج!"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="أفضل منصّة"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:lineSpacingExtra="30sp"
android:text="لتعليم البرمجة!"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
الفرق بين خاصيّة layout_gravity وخاصيّة gravity
توجد خاصيّة أخرى غير layout_gravity تُسمّى gravity، والفرق بينهما هو أنَّ الأولى تُعبِّر عن وجهة العُنصر التي يُفضّلها في النموذج الذي يحتويه، أمّا الأخيرة، فهي لما يوجد بداخل العنصر نفسه من مُحتوى، كالكلمات الموجودة بداخل عناصر TextView، فلو قمنا بتحديد خاصيّة gravity لهذا العنصر لتكون center، فهذا تقريباً يعمل عمل خيار “Text align center” الشهير في Microsoft Word. فبالمختصر، لتحريك العنصر كاملاً (بما يحتويه)، يتمّ استخدام خاصيّة layout_gravity (وهذا ما نحتاجه هنا)، أمّا لتحريك محتوى العنصر في العنصر نفسه، فيتم استخدام خاصيّة gravity.
لنوضِّح ذلك أكثر، سنقوم باستعراض مثال بسيط لواجهة تحتوي على 4 عناصر من نوع TextView، بحيث أنَّ العنصر الأوّل سنستخدم فيه خاصيّة layout_gravity لمحاذاته للوسط، وسنجعل عرضه في الواجهة (أي layout_width) هو wrap_content (أي سيكون العرض فقط بمقدار ما يحتاجه العنصر)، والعنصر الثاني سنستخدم فيه نفس الخاصيّة، ولكن سنجعل عرضه match_parent (وهنا سيكون عرضه ممتدّاً على طول الواجهة). أمّا العنصران الآخيران، فسنستخدم فيهم خاصيّة gravity ونحدّد قيمتها “center”، وسنجعل أحدهما بعرض match_parent، وأمّا الآخر فسيكون بعرض wrap_content. سنجعل خلفيّة هذه العناصر جميعها سوداء بهدف التمييز بينها ومعرفة عرض كلّ منها. وبذلك، فستظهر الواجهة بالشكل الآتي:
لاحظ كيف أنَّ خاصيّة gravity لم تحاذِ عناصرها إلى الوسط (يمكن ملاحظة ذلك في النصّ الأخير)، وإنّما قامت بمحاذاة ما يتضمّنه العنصر إلى الوسط (يمكن ملاحظة ذلك في النصّ الثالث)، أمّا بالنسبة للعنصر الأوّل، والذي قد استخدمنا فيه خاصيّة layout_gravity، فقد تمَّ نقله كاملاً إلى الوسط بكامل محتواه، ولاحظ أيضاً أنَّ العنصر الثاني لم يحدث عليه أي تغيير، وذلك لأنَّ خاصيّة layout_gravity لا تكترث بما يوجد في داخل العنصر، وإنّما تنظر إلى العنصر كاملاً على أنّه قطعة واحدة. يمكنك دراسة الكود أدناه لفهم مبدأ عمل الواجهة السابقة:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
androidrientation="vertical"
tools:context=".MainActivity">
<Space
android:layout_width="match_parent"
android:layout_height="100dp" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@android:color/background_dark"
android:text="هذا العنصر يستخدم خاصيّة layout_gravity"
android:textColor="#ff0000"
android:textSize="18sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="100dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@android:color/background_dark"
android:text="هذا العنصر أيضاً يستخدم خاصيّة layout_gravity"
android:textColor="#ff0000"
android:textSize="18sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="100dp" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/background_dark"
android:gravity="center"
android:text="هذا العنصر يستخدم خاصيّة gravity"
android:textColor="#ff0000"
android:textSize="18sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="100dp" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/background_dark"
android:gravity="center"
android:text="هذا العنصر أيضاً يستخدم خاصيّة gravity"
android:textColor="#ff0000"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
FrameLayout
يدعم نموذج FrameLayout خاصيّة layout_gravity للعناصر التي يحتويها، لذا يمكننا استخدام نفس الطريقة المُتّبعة في LinearLayout لمحاذاة العناصر إلى الوسط.
مثال
سنقوم باستعراض مثال عملي بسيط كواجهة لتسجيل الدخول إلى موقع برمج، بحيث سنقوم باستخدام ConstraintLayout كنموذج رئيس، وسيحتوي على بعض العناصر المُرتّبة بحسب الغرض، كما سنستخدم LinearLayout لاحتواء زرّي تسجيل الدخول وتسجيل حساب جديد:
ما يلي الكود الخاصّ بالواجهة:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
androidrientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Barmej.com"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:textSize="18sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<TextView
android:id="@+id/usernameLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="أدخل اسم المستخدم:"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="@+id/username"
app:layout_constraintTop_toBottomOf="@+id/title" />
<EditText
android:id="@+id/password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:gravity="right"
android:inputType="textPassword"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/username" />
<TextView
android:id="@+id/passwordLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="كلمة المرور:"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="@+id/password"
app:layout_constraintTop_toTopOf="@+id/password" />
<LinearLayout
android:id="@+id/buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
androidrientation="horizontal"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/passwordLabel">
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="تسجيل الدخول" />
<Button
android:id="@+id/register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="حساب جديد" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
The post محاذاة عناصر الواجهة إلى الوسط appeared first on مدونة برمج.