פריסות בתצוגות
פריסה מגדירה את המבנה של ממשק משתמש באפליקציה, למשל
ה
פעילות. כל הרכיבים ב
נבנו לפי היררכיה
View
והקבוצה
ViewGroup
אובייקטים. View
בדרך כלל משרטט משהו שהמשתמש יכול לראות
ליצור איתם אינטראקציה. ViewGroup
הוא קונטיינר בלתי נראה שמגדיר
מבנה הפריסה של View
ושל ViewGroup
אחרים
של האובייקטים, כפי שמוצג באיור 1.
לרוב האובייקטים View
נקראים ווידג'טים והם יכולים להיות
הרבה תתי-מחלקות,
Button
או
TextView
ViewGroup
אובייקטים נקראים בדרך כלל פריסות ויכולים להיות אחד
סוגים רבים שמספקים מבנה פריסה שונה, כמו
LinearLayout
או
ConstraintLayout
.
יש שתי דרכים להצהיר על פריסה:
- להצהיר על רכיבים בממשק המשתמש ב-XML. ב-Android יש קובץ XML פשוט
שמתאים לכיתות ולכיתות המשנה של
View
, כמו אלו שמיועדות לווידג'טים ולפריסות. אפשר גם להשתמש עורך הפריסה לבניית ה-XML באמצעות ממשק גרירה ושחרור. - יצירת רכיבי פריסה מיידיים בזמן ריצה האפליקציה שלך יכולה ליצור
אובייקטים של
View
ו-ViewGroup
וביצוע שינויים בהם באופן פרוגרמטי.
הצהרה על ממשק המשתמש ב-XML מאפשרת להפריד את הצגת האפליקציה בקוד ששולט בהתנהגות שלו. השימוש בקובצי XML מקל גם על לספק פריסות שונות למסכים בגדלים שונים ולכיוונים שונים. הדבר לדיון נוסף בנושא תמיכה במסך אחר גדלים .
מסגרת Android נותנת לך את הגמישות להשתמש באחד או בשניהם השיטות האלה כדי לבנות את ממשק המשתמש של האפליקציה. לדוגמה, אתם יכולים להצהיר על זכויות היוצרים של האפליקציה שלכם פריסות ברירת המחדל ב-XML, ולאחר מכן לשנות את הפריסה בזמן הריצה.
כתיבת ה-XML
בעזרת אוצר המילים של XML ב-Android, אפשר לעצב במהירות פריסות של ממשק המשתמש שהם מכילים, באותו אופן שבו יוצרים דפי אינטרנט ב-HTML באמצעות סדרה של אלמנטים שהוצבו בו.
כל קובץ פריסה חייב להכיל רק רכיב בסיס אחד, חייב להיות
אובייקט View
או ViewGroup
. אחרי שמגדירים את השורש
ניתן להוסיף עוד אובייקטי פריסה או ווידג'טים כרכיבי צאצא
ליצור בהדרגה היררכיית View
שמגדירה את הפריסה שלך. עבור
הנה פריסת XML שמשתמשת ב-LinearLayout
אנכי כדי
שומרים את TextView
ואת Button
:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>
אחרי שמצהירים על הפריסה ב-XML, שומרים את הקובץ עם
תוסף אחד (.xml
) בres/layout/
של פרויקט Android שלך
כך שהוא יוכל הידור כראוי.
למידע נוסף על התחביר של קובץ XML לפריסה: משאב פריסה.
צריך לטעון את משאב ה-XML
כשיוצרים את האפליקציה, כל קובץ פריסת XML עובר הידור
משאב View
. צריך לטעון את משאב הפריסה באפליקציה
Activity.onCreate()
הטמעת קריאה חוזרת (callback). כדי לעשות זאת, צריך להתקשר
setContentView()
,
ומעבירים לו את ההפניה למשאב הפריסה בתבנית:
R.layout.layout_file_name
. לדוגמה, אם קובץ ה-XML
הפריסה נשמרה בשם main_layout.xml
, ניתן לטעון אותה
Activity
באופן הזה:
Kotlin
fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.main_layout) }
Java
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); }
ה-framework של Android מפעיל את שיטת הקריאה החוזרת onCreate()
ב-
שלך ב-Activity
כשנשיק את Activity
. לקבלת מידע נוסף
מידע על מחזורי חיים של פעילות,
מבוא ל
פעילויות נוספות.
מאפיינים
כל אובייקט View
ו-ViewGroup
תומך משלו
מגוון של מאפייני XML. חלק מהמאפיינים ספציפיים לView
לאובייקט. לדוגמה, הפקודה TextView
תומכת בפונקציה textSize
. עם זאת, המאפיינים האלה עוברים בירושה גם לכל View
אובייקטים שמרחיבים את המחלקה הזו. חלקם משותפים לכל View
כי הם עוברים בירושה ממחלקת השורש View
, כמו
המאפיין id
. מאפיינים אחרים נחשבים לפריסה
, שהם מאפיינים שמתארים כיוונים מסוימים של הפריסה
של האובייקט View
, כפי שהוגדר על ידי ההורה של האובייקט
אובייקט ViewGroup
.
מזהה
לכל אובייקט View
יכול להיות מזהה מספר שלם שמשויך אליו
לזהות באופן ייחודי את View
בעץ. כשהאפליקציה
שעברו הידור, למזהה הזה יש הפניה למספר שלם, אבל בדרך כלל המזהה מוקצה
בקובץ ה-XML של הפריסה, כמחרוזת במאפיין id
. זהו
מאפיין XML המשותף לכל האובייקטים View
, והוא מוגדר באמצעות
כיתה אחת (View
). אתם משתמשים בה לעיתים קרובות. התחביר של מזהה בתוך
תג XML הוא התג הבא:
android:id="@+id/my_button"
הסמל at (@) בתחילת המחרוזת מציין
מנתח ה-XML מנתח ומרחיב את שאר מחרוזת המזהה ומזהה אותה בתור
משאב מזהה. סמל הפלוס (+) מציין שזה שם של משאב חדש
שצריך ליצור ולהוסיף למשאבים שלכם בR.java
חדש.
במסגרת Android יש הרבה משאבי זיהוי אחרים. כאשר מפנים
מזהה משאב של Android, אין צורך בסמל הפלוס, אבל חייבים להוסיף את
מרחב שמות של חבילה android
באופן הבא:
android:id="@android:id/empty"
מרחב השמות של החבילה android
מציין שהתייחסת אליו
מזהה ממחלקת המשאבים android.R
ולא מהמחלקה המקומית
במחלקת המשאבים.
כדי ליצור תצוגות ולהפנות אליהן מהאפליקציה, אפשר להשתמש דפוס:
- מגדירים תצוגה בקובץ הפריסה ומקצים לה מזהה ייחודי, כמו
בדוגמה הבאה:
<Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text"/>
- יוצרים מופע של אובייקט ה-View ומצלמים אותו מהפריסה,
בדרך כלל
onCreate()
כפי שאפשר לראות בדוגמה הבאה:Kotlin
val myButton: Button = findViewById(R.id.my_button)
Java
Button myButton = (Button) findViewById(R.id.my_button);
חשוב להגדיר מזהים לאובייקטים של תצוגה מפורטת כשיוצרים
RelativeLayout
בפריסה יחסית, תצוגות אחות יכולות להגדיר את הפריסה שלהן ביחס לאחרת
לתצוגה אחות, שאליה מפנה המזהה הייחודי.
המזהה לא חייב להיות ייחודי לאורך כל העץ, אבל הוא צריך להיות ייחודיות בחלק של העץ שאתם מחפשים. בדרך כלל מדובר לכן מומלץ להפוך אותו לייחודי ככל האפשר.
פרמטרים של פריסה
מגדירים מאפייני פריסת XML בשם layout_something
פרמטרים של פריסה עבור View
שמתאימים ל-
ViewGroup
המכשיר נמצא.
כל מחלקה ViewGroup
מטמיעה מחלקה פנימית שמתרחבת
ViewGroup.LayoutParams
.
תת-המחלקה הזו מכילה סוגי נכסים שמגדירים את הגודל והמיקום של כל אחד מהם.
תצוגת צאצא, בהתאם לקבוצת התצוגה המפורטת. כפי שמוצג באיור 2, הורה
לקבוצת התצוגה הזו מוגדרים פרמטרים של פריסה לכל תצוגת צאצא, כולל הצאצא.
קבוצת תצוגה מפורטת.
לכל תת-מחלקה ב-LayoutParams
יש תחביר משלה להגדרה
ערכים. כל רכיב צאצא צריך להגדיר LayoutParams
שמתאים להורה שלו, למרות שהוא עשוי גם להגדיר
LayoutParams
לילדים שלו.
כל קבוצות התצוגות המפורטות כוללות רוחב וגובה, באמצעות המאפיין layout_width
ו-layout_height
, וכל תצוגה מפורטת נדרשת כדי להגדיר אותם. הרבה
LayoutParams
כוללים שוליים וגבולות אופציונליים.
אפשר לציין רוחב וגובה במידות מדויקות, אבל יכול להיות שלא כדאי לעשות זאת לעיתים קרובות. לעיתים קרובות יותר משתמשים באחד מהקבועים האלה כדי להגדיר רוחב או גובה:
wrap_content
: מנחה את התצוגה להתאים את הגודל שלו שנדרשים על ידי התוכן שלו.match_parent
: הגדרה של גודל החשיפה של ההורה לאפשר לקבוצת צפיות.
באופן כללי, לא מומלץ לציין רוחב וגובה של הפריסה באמצעות
יחידות מוחלטות כמו פיקסלים. גישה טובה יותר היא להשתמש במדידות יחסיות,
כמו יחידות פיקסלים שלא תלויות בדחיסות (dp), wrap_content
או
match_parent
, מפני שהיא עוזרת להציג את האפליקציה בצורה תקינה
מגוון גדלים של מסכים במכשירים. סוגי המדידה הקבילים מוגדרים ב:
משאב פריסה.
מיקום הפריסה
בתצוגה יש גיאומטריה מלבנית. יש לו מיקום, מבוטא בזוג קואורדינטות left ו-top (ראש הדף) ושני מאפיינים, שמבוטאים רוחב וגובה. היחידה של המיקום והמידות היא הפיקסל.
כדי לאחזר מיקום של תצוגה, צריך להפעיל את השיטות
getLeft()
וגם
getTop()
.
הראשונה מחזירה את הקואורדינטה שמאלית (x) של המלבן שמייצג
את התצוגה. השנייה מחזירה את הקואורדינטה העליונה (y) של המלבן
שמייצגים את התצוגה. שיטות אלה מחזירות את מיקום התצוגה ביחס
ההורה שלו. לדוגמה, אם getLeft()
מחזירה 20, המשמעות היא
התצוגה ממוקמת 20 פיקסלים מימין לקצה השמאלי של הקצה
הורה.
בנוסף, יש שיטות נוחות למניעת חישובים מיותרים:
כלומר
getRight()
וגם
getBottom()
.
השיטות האלה מחזירות את הקואורדינטות של הקצה הימני והתחתון של
שמייצג את התצוגה. לדוגמה, השיחה אל getRight()
היא
בדומה לחישוב הבא: getLeft() + getWidth()
.
גודל, מרווח פנימי ושוליים
גודל התצוגה מצוין באמצעות רוחב וגובה. לתצוגה מפורטת יש שני צמדים של ערכי רוחב וגובה.
הצמד הראשון נקרא רוחב נמדד
הגובה שנמדד. המאפיינים האלה מגדירים את הגודל הרצוי של התצוגה
בתוך ההורה שלו. כדי לקבל את המידות שנמדדו, צריך לשלוח קריאה
getMeasuredWidth()
וגם
getMeasuredHeight()
.
הצמד השני נקרא width ו-height, או לפעמים
רוחב שרטוט וגובה שרטוט. המאפיינים האלה מגדירים את
הגודל בפועל של התצוגה על המסך, בזמן הציור ואחרי הפריסה. האלה
עשויים להיות שונים מהרוחב והגובה שנמדדו, אבל לא חייבים להיות בהם. שלך
יכול לקבל את הרוחב והגובה באמצעות קריאה
getWidth()
וגם
getHeight()
.
כדי למדוד את מידות המודעה, המרווח הפנימי של התצוגה נלקח בחשבון. המרווח הפנימי
מבוטאת בפיקסלים בחלקים השמאליים, העליונים, הימניים והתחתונים של התצוגה.
ניתן להשתמש במרווח פנימי כדי לקזז את תוכן התצוגה במספר ספציפי של
פיקסלים. לדוגמה, מרווח פנימי שמאלי של שני פיקסלים דוחף את תוכן התצוגה בשני פיקסלים.
מימין לקצה השמאלי. אפשר להגדיר מרווח פנימי באמצעות
setPadding(int, int, int, int)
ולהרצת שאילתה על ידי
getPaddingLeft()
,
getPaddingTop()
,
getPaddingRight()
,
וגם
getPaddingBottom()
למרות שבתצוגה אפשר להגדיר מרווח פנימי, היא לא תומכת בשוליים. אבל, לפעמים
כן תומכות בשולי רווח. צפייה
ViewGroup
והקבוצה
ViewGroup.MarginLayoutParams
אפשר לקבל מידע נוסף.
למידע נוסף על מאפיינים, אפשר לעיין במאמר מאפיין.
מלבד הגדרה של שוליים ומרווח פנימי באופן פרוגרמטי, אפשר גם להגדיר אותם בפריסות ה-XML, כמו שאפשר לראות בדוגמה הבאה:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:padding="8dp" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:paddingBottom="4dp" android:paddingEnd="8dp" android:paddingStart="8dp" android:paddingTop="4dp" android:text="Hello, I am a Button" /> </LinearLayout>
בדוגמה שלמעלה רואים שוליים ומרווח פנימי שהוחל.
ב-TextView
יש שוליים ומרווח פנימי אחידים מסביב, וגם
Button
מראה איך ניתן ליישם אותם בנפרד
הקצוות.
פריסות נפוצות
כל תת-מחלקה במחלקה ViewGroup
מספקת דרך ייחודית
להציג את התצוגות שהוצבו בו. סוג הפריסה הגמישה ביותר
שמספק את הכלים הטובים ביותר לשמירה על היררכיית פריסה נמוכה,
ConstraintLayout
הנה כמה מסוגי הפריסה הנפוצים שמובְנים במכשיר ה-Android הפלטפורמה.
מארגנת את הצאצאים בשורה אופקית או אנכית אחת ויוצרת סרגל גלילה אם אורך החלון חורג מאורך המסך.
יצירת רשימות דינמיות
אם התוכן לפריסה דינמי או לא קבוע מראש, אפשר
להשתמש
RecyclerView
או
תת-מחלקה של
AdapterView
.
בדרך כלל עדיף להשתמש ב-RecyclerView
כי הוא משתמש בזיכרון
בצורה יעילה יותר מאשר AdapterView
.
פריסות נפוצות שאפשר להשתמש בהן בעזרת RecyclerView
וגם
AdapterView
כוללות:
RecyclerView
מציע עוד אפשרויות ו
האפשרות
ליצור התאמה אישית
מנהל הפריסה.
מילוי תצוגת מתאם בנתונים
אפשר לאכלס
AdapterView
כמו ListView
או
GridView
על ידי
הפונקציה מקשרת את המופע של AdapterView
Adapter
,
שמאחזר נתונים ממקור חיצוני ויוצר View
שמייצג כל רשומת נתונים.
ב-Android יש כמה מחלקות משנה של Adapter
שימושיות
לאחזור סוגים שונים של נתונים וליצירת תצוגות
AdapterView
. שני המתאמים הנפוצים ביותר הם:
ArrayAdapter
- יש להשתמש במתאם הזה כאשר מקור הנתונים הוא מערך. כברירת מחדל,
הפונקציה
ArrayAdapter
יוצרת תצוגה לכל פריט במערך באמצעות קריאהtoString()
על כל פריט ומציבים את התוכן בTextView
.לדוגמה, אם יש מערך של מחרוזות שאתם רוצים להציג
ListView
, צריך לאתחלArrayAdapter
חדש באמצעות כדי לציין את הפריסה לכל מחרוזת ומערך המחרוזת:Kotlin
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
Java
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray);
הארגומנטים של ה-constructor האלה הם:
- האפליקציה שלך
Context
- הפריסה שמכילה
TextView
לכל מחרוזת ב- מערך - מערך המחרוזת
ואז להתקשר
setAdapter()
ב-ListView
שלך:Kotlin
val listView: ListView = findViewById(R.id.listview) listView.adapter = adapter
Java
ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter);
כדי להתאים אישית את המראה של כל פריט אפשר לשנות את המאפיין של
toString()
לאובייקטים במערך. או כדי ליצור תצוגה של כל פריט שהוא לאTextView
- לדוגמה, אם רוציםImageView
לכל פריט במערך – מרחיבים את המחלקהArrayAdapter
לשנותgetView()
כדי להחזיר את סוג התצוגה הרצויה לכל פריט. - האפליקציה שלך
SimpleCursorAdapter
- יש להשתמש במתאם הזה כאשר הנתונים מגיעים
Cursor
. כשמשתמשים ב-SimpleCursorAdapter
, צריך לציין את הפריסה שתשמש כל שורה ב-Cursor
ואילו עמודותCursor
שברצונך להוסיף לתצוגות של הפריסה הרצויה. לדוגמה, אם אתה רוצה ליצור רשימה של שמות ומספרי טלפון של אנשים אפשר להריץ שאילתה שמחזירהCursor
שכוללות שורה לכל אדם ועמודות עם השמות והמספרים. שלך ליצור מערך מחרוזת שמציין אילו עמודות הערך הרצוי שלCursor
בפריסה של כל תוצאה ומספר שלם מערך שמציין את התצוגות המתאימות שצריכות להיות לכל עמודה ממוקם:Kotlin
val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER) val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
Java
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER}; int[] toViews = {R.id.display_name, R.id.phone_number};
כשיוצרים את
SimpleCursorAdapter
, מעבירים את לשימוש בכל תוצאה, ה-Cursor
שמכיל את ושני המערכים האלה:Kotlin
val adapter = SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0) val listView = getListView() listView.adapter = adapter
Java
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); ListView listView = getListView(); listView.setAdapter(adapter);
לאחר מכן הפרמטר
SimpleCursorAdapter
יוצר תצוגה מפורטת לכל שורהCursor
באמצעות הפריסה שסופקה על ידי הוספת כל אחד מהם פריט אחד (fromColumns
) ב-toViews
המתאים צפייה.
אם במהלך חיי האפליקציה משנים את הנתונים הבסיסיים
נקרא על ידי המתאם,
notifyDataSetChanged()
פעולה זו מיידעת את התצוגה המצורפת שהנתונים השתנו והם מתרעננים
עצמו.
טיפול באירועי קליקים
אפשר להגיב לאירועים מסוג קליק על כל פריט ב-AdapterView
באמצעות יישום של
AdapterView.OnItemClickListener
גרפי. לדוגמה:
Kotlin
listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id -> // Do something in response to the click. }
Java
// Create a message handling object as an anonymous class. private OnItemClickListener messageClickedHandler = new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { // Do something in response to the click. } }; listView.setOnItemClickListener(messageClickedHandler);
מקורות מידע נוספים
איך משתמשים בפריסות חמנית אפליקציית הדגמה ב-GitHub.