Εξηγούμε τα βασικά του LinearLayout — βασική ViewGroup στο Android SDK για στοίχιση θυγατρικών στοιχείων σε μία γραμμή: κάθετα (LinearLayout.VERTICAL) ή οριζόντια (LinearLayout.HORIZONTAL). Το LinearLayout παραμένει ο απλούστερος και ταχύτερος τρόπος για να δημιουργήσετε μια γραμμή κουμπιών, μια λίστα ρυθμίσεων ή μια φόρμα εισαγωγής, όταν η πολυπλοκότητα της διάταξης δεν υπερβαίνει τα 5–10 στοιχεία. Τα χαρακτηριστικά layout_weight και orientation διαχειρίζονται την κατανομή του χώρου και την κατεύθυνση. Λεπτομερής προδιαγραφή — στο LinearLayout API Reference.
Κύρια σημεία
LinearLayout — μία από τις πρώτες ViewGroup στο 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: πρώτο child — y=0, δεύτερο — y=prev.bottom + divider.hidden, και ούτω καθεξής. Στον HORIZONTAL — στον άξονα X. Το Divider (διαχωριστικό) ορίζεται μέσω 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, size ή height τους. Αυτό κάνει μια γραμμή με εικονίδιο, τίτλο και περιγραφή οπτικά τακτοποιημένη: το κείμενο δεν πηδά πάνω-κάτω.
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, η διαφορά παραμένει ως κενός χώρος.
Η φόρμα σύνδεσης αποτελείται από τρία στοιχεία: πεδίο email (καταλαμβάνει 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 τρίψιμο."
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 μs. Για μια λίστα 20 στοιχείων με 3 επίπεδα ένθεσης, η καθυστέρηση μπορεί να φτάσει τα 3 ms ανά στοιχείο — αυτό είναι αισθητό jank κατά την κύλιση. Το ConstraintLayout λύνει αυτό το πρόβλημα μέσω επίπεδης ιεραρχίας, αντικαθιστώντας 3–4 ένθετα LinearLayout με ένα δοχείο με περιορισμούς.
Σύσταση: χρησιμοποιήστε LinearLayout για απλές γραμμικές διατάξεις (έως 10 στοιχεία, ένα επίπεδο ένθεσης). Για κάρτες λίστας, φόρμες με διαφορετική στοίχιση και οθόνες με δομή πίνακα, επιλέξτε ConstraintLayout. Για επαναλαμβανόμενα στοιχεία στο RecyclerView, χρησιμοποιήστε ConstraintLayout στο αρχείο διάταξης του στοιχείου — αυτό είναι κρίσιμο για την απόδοση κύλισης.
Συχνές ερωτήσεις
Η συνηθέστερη αιτία — το μέγεθος στην κατεύθυνση δεν έχει οριστεί σε 0dp. Για διάταξη HORIZONTAL χρειάζεται android:layout_width="0dp", για VERTICAL — android:layout_height="0dp". Αν το στοιχείο έχει wrap_content ή match_parent, το weight μπορεί να μην λειτουργήσει ή να δώσει απροσδόκητο αποτέλεσμα. Δεύτερη αιτία — το weightSum στον γονέα είναι μικρότερο από το άθροισμα weight των παιδιών. Τρίτη — χρήση 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, μπορεί να μείνει κενός χώρος μεταξύ τους λόγω λανθασμένου υπολογισμού. Για μηδενικά κενά, ορίστε σε όλα τα παιδιά margin=0dp και αφαιρέστε το divider.
Για απλές μονής κατεύθυνσης διατάξεις (1–5 στοιχεία σε γραμμή/στήλη) το LinearLayout είναι ελαφρώς ταχύτερο — δεν ξοδεύει πόρους για τον υπολογισμό περιορισμών. Για σύνθετες διατάξεις (πάνω από 5 στοιχεία, πλέγματα, διαφορετικούς τύπους στοίχισης) το ConstraintLayout είναι ταχύτερο επειδή χρησιμοποιεί επίπεδη ιεραρχία αντί για ένθετα LinearLayout. Σύμφωνα με δοκιμές της Google (Android Performance Blog), το ConstraintLayout κερδίζει σε διατάξεις που απαιτούν 3+ επίπεδα ένθεσης LinearLayout.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης