מדריך למתחילים · LinearLayout · שיעור כפול

לוח תוצאות
מסדרים מסך עם LinearLayout

בונים אפליקציה שסופרת נקודות במשחק בין שתי קבוצות. בדרך לומדים איך מסדרים רכיבים על המסך: מה למעלה, מה למטה, ומה זה ליד זה.

גמר הליגה
שריקת פתיחה
הנשרים
21
+3
+2
+1
הכרישים
18
+3
+2
+1
איפוס
מה בונים היום: מסך עם כותרת, שתי קבוצות זו ליד זו, לכל קבוצה ניקוד גדול ושלושה כפתורים, וכפתור איפוס למטה. קודם חוזרים על מה שנלמד בשני המדריכים הקודמים, ואז מכירים את LinearLayout, קינון, weight, margin ו-padding, ואת המאפיינים של כפתור.
ניקוד

איך צוברים נקודות

הספורט, שמות הקבוצות והצבעים הם בחירה שלכם: כדורסל, כדורגל, פינג-פונג, קלפים. המדריך כתוב על כדורסל (מאפשר הוספה של 3 נק', 2 נק', או 1 נק').

חלקמה עושיםנקודותזמן משוער
חזרהפרויקט חדש בלי מדריך, מהזיכרון1020 דק'
הפרויקטלוח תוצאות עובד לשתי קבוצות, עם איפוס4045 דק'
נקודת בדיקהמסבירים למורה שלושה דברים קצרים1010 דק'
הרחבה 1עיצוב הקבוצות10בזמן שנשאר ובבית
הרחבה 2כפתור תיקון טעות15
הרחבה 3סיום משחק והכרזת מנצח15
מסלול מתקדםשלוש משימותבונוס עד 30
חוק אחד חשוב

ניקוד על הרחבות ועל המסלול המתקדם נרשם רק אחרי שעברתם את נקודת הבדיקה מול המורה. אפליקציה שעובדת בלי שאתם יודעים להסביר אותה לא נחשבת.

חלק 1

חזרה: מהזיכרון, בלי מדריך

  1. צרו פרויקט חדש עם שם משמעותי - למשל ScoreBoard. השם באנגלית בלבד, בלי רווחים ובלי תווים מיוחדים. תבנית Empty Views Activity, שפה Java, ‏Minimum SDK ‏API 26, ‏Build configuration language ‏Groovy DSL.
  2. חובה, לפני שמוסיפים רכיב כלשהו: פתחו את activity_main.xml במצב Code, מחקו את כל התוכן שלו והדביקו במקומו את שלד ה-LinearLayout שמופיע מתחת לרשימה.
  3. בתוך השלד הוסיפו TextView: id בשם tvTitle, טקסט עם שם המשחק שלכם, וגודל טקסט 28sp.
  4. מתחתיו הוסיפו כפתור עם id בשם btnWhistle וטקסט "שריקת פתיחה". לחיצה עליו מציגה Toast: "המשחק התחיל!".
  5. ב-colors.xml הוסיפו צבע חדש בשם screen_bg (צבע בהיר לבחירתכם), והגדירו אותו כרקע של המסך.
  6. הריצו את האפליקציה ובדקו שהכול עובד.
בוחרים Empty Views Activity, לא Empty Activity

במסך בחירת התבנית יש שתי תבניות עם שם כמעט זהה, זו ליד זו. הנכונה היא Empty Views Activity, עם המילה Views.

איך מזהים שבחרתם לא נכון: במסך הבא אין שדה Language, ומתחת לכותרת כתוב "Jetpack Compose". במקרה כזה לחצו Previous, בחרו Empty Views Activity, ורק אז בחרו Java.

השלד שמדביקים ב-activity_main.xml

res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <!-- את הרכיבים שלכם מוסיפים כאן, בין שתי התגיות -->

</LinearLayout>
למה מתחילים מהשלד הזה

פרויקט חדש נפתח עם קופסה מסוג ConstraintLayout. בקופסה כזו כל רכיב חייב להיות "קשור" לשכנים שלו, ורכיב שלא נקשר מסומן בשגיאה אדומה וקופץ לפינת המסך. זו הסיבה לרוב התקלות בתחילת הדרך.

ב-LinearLayout אין צורך לקשור כלום: כל רכיב שמוסיפים מופיע מתחת לקודם. מה בדיוק כתוב בשלד תלמדו בחלק 2.

אל תמחקו את השורה android:id="@+id/main"

ב-MainActivity.java יש שורה ש-Android Studio כתב בשבילכם ומחפשת רכיב בשם main. אם ה-id הזה חסר, תקבלו שגיאה אדומה על R.id.main והאפליקציה לא תיבנה.

בשלב הזה הרכיבים יופיעו אחד מתחת לשני, צמודים לצד המסך. את היישור למרכז נעשה בחלק 3. חשוב לדייק בשמות (tvTitle, btnWhistle, screen_bg) כי ההמשך משתמש בהם.

רמז: איפה כותבים XML ואיך מוסיפים רכיב עם id

פתחו את app > res > layout > activity_main.xml. בפינה הימנית העליונה של העורך יש שלושה מצבים: Code, Split, Design. עברו ל-Code. רכיב חדש כותבים בתוך השלד, במקום שורת ההערה. כך נראה TextView עם id:

<TextView
    android:id="@+id/tvTitle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="גמר הליגה"
    android:textSize="28sp" />

כפתור נכתב באותה צורה, עם <Button במקום <TextView. מספיק להקליד <Bu ולבחור מההשלמה האוטומטית.

רמז: איפה colors.xml ואיך מוסיפים צבע

הקובץ נמצא ב-app > res > values > colors.xml. מוסיפים שורה לפני התגית הסוגרת </resources>:

<color name="screen_bg">#FFF8EE</color>

ובתגית הפותחת של ה-LinearLayout ב-activity_main.xml, כשורה נוספת:

android:background="@color/screen_bg"
רמז: הקוד של Toast בלחיצה על כפתור

ב-MainActivity.java, בתוך onCreate, אחרי השורות שכבר כתובות שם:

Button btnWhistle = findViewById(R.id.btnWhistle);
btnWhistle.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(MainActivity.this, "המשחק התחיל!", Toast.LENGTH_SHORT).show();
    }
});

אם Button, View או Toast מסומנים באדום, עמדו על המילה ולחצו Alt+Enter ואז Import class.

שימו לב שכתוב MainActivity.this ולא this: בתוך ה-OnClickListener המילה this לבדה מצביעה על המאזין עצמו ולא על המסך.

סיימתם את החזרה כש...

האפליקציה רצה, רואים את שם המשחק על רקע בצבע שבחרתם, ולחיצה על הכפתור מציגה את ההודעה. קראו למורה לרישום 10 הנקודות.

חלק 2

הסבר: מה זה Layout

בחלק 1 הדבקתם שלד של LinearLayout בלי לדעת מה הוא. עכשיו מבינים אותו. עד עכשיו שמתם רכיבים על המסך בלי לחשוב איפה הם יושבים. באפליקציה אמיתית צריך להחליט: מה למעלה, מה למטה, מה זה ליד זה. מי שמחליט על כך הוא ה-Layout.

Layout הוא קופסה שקופה שמחזיקה בתוכה רכיבים ומסדרת אותם לפי חוק. לקופסה מהסוג LinearLayout יש חוק פשוט מאוד: היא מסדרת את הרכיבים שבתוכה בקו אחד. או אחד מתחת לשני (vertical), או אחד ליד השני (horizontal). כמו מדף ספרים: ספרים עומדים בשורה, או מונחים בערימה.

רכיב 1
רכיב 2
רכיב 3
orientation="vertical"
ערימה: אחד מתחת לשני
1
2
3
orientation="horizontal"
שורה: אחד ליד השני

קופסה בתוך קופסה

מה עושים כשרוצים גם וגם? כותרת למעלה, מתחתיה שתי קבוצות זו ליד זו, ולמטה כפתור. הפתרון: שמים LinearLayout בתוך LinearLayout. לזה קוראים קינון. כך בנוי המסך שלנו:

LinearLayout אנכי (כל המסך)
כותרת
כפתור שריקה
LinearLayout אנכי
שם
ניקוד
+3 +2 +1
LinearLayout אנכי
שם
ניקוד
+3 +2 +1
כפתור איפוס
שלוש רמות: קופסה אנכית גדולה, בתוכה שורה אופקית, ובתוך השורה שתי עמודות אנכיות.

ארבעה מושגים שתפגשו בקוד

מושגמה הוא אומרדימוי
match_parentתהיה גדול כמו הקופסה שמחזיקה אותךשטיח מקיר לקיר
wrap_contentתהיה גדול רק כמו התוכן שלךחולצה במידה שלך
layout_weightאיך מחלקים את המקום הפנוי בין הרכיבים. משקל שווה, חלק שווהחלוקת פיצה: לכל אחד 1, כולם מקבלים אותו דבר
padding ו-marginpadding הוא רווח בתוך הרכיב, בין הגבול לתוכן. margin הוא רווח מחוץ לרכיב, בינו לבין השכניםpadding: ריפוד בתוך קופסה. margin: מרחק בין שתי קופסאות
weight 1
weight 1
weight 2
weight 1
משקל 1 ו-1: חצי-חצי. משקל 2 ו-1: שני שלישים ושליש.
margin
padding
התוכן
הקו המלא הוא גבול הרכיב. padding בפנים, margin בחוץ.
ועוד צמד שמתבלבלים בו

gravity קובע איפה התוכן יושב בתוך הרכיב (למשל טקסט ממורכז בתוך TextView). layout_gravity קובע איפה הרכיב עצמו יושב בתוך הקופסה שמחזיקה אותו. תפגשו את שניהם בהמשך.

חלק 3

בונים צעד-צעד

עובדים בשני קבצים: activity_main.xml (איך המסך נראה) ו-MainActivity.java (מה קורה כשלוחצים). אחרי כל תיבה כחולה של "הריצו ובדקו" מריצים ובודקים. לא ממשיכים הלאה עם שגיאה.

1

פותחים את קובץ המסך במצב Code

בעץ הקבצים משמאל: app > res > layout > activity_main.xml. לחיצה כפולה. בפינה הימנית העליונה של העורך בחרו Code (או Split אם אתם רוצים לראות תצוגה מקדימה ליד הקוד).

2

מיישרים את הכותרת ואת הכפתור למרכז

הקובץ שלכם כבר מכיל LinearLayout עם כותרת וכפתור מחלק 1. עדכנו אותו כך שייראה כמו הקוד הבא. שלוש שורות חדשות: android:gravity="center" בכותרת, ו-android:layout_gravity="center_horizontal" ו-android:layout_marginTop="8dp" בכפתור. ודאו גם שהרוחב של הכותרת הוא match_parent ושל הכפתור wrap_content.

res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/screen_bg"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="גמר הליגה"
        android:textSize="28sp" />

    <Button
        android:id="@+id/btnWhistle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="8dp"
        android:text="שריקת פתיחה" />

</LinearLayout>
מה כתבנו פה

orientation="vertical": הרכיבים מסודרים אחד מתחת לשני. padding="16dp": רווח פנימי של 16 מכל הצדדים, כדי ששום דבר לא יידבק לקצה המסך.

בכותרת: הרוחב match_parent (כל רוחב המסך) ו-gravity="center" ממרכז את הטקסט בתוכה.

בכפתור: הרוחב wrap_content (רק כמו הטקסט), ולכן ממרכזים את הכפתור עצמו עם layout_gravity.

הריצו ובדקו

הכותרת למעלה באמצע, הכפתור מתחתיה באמצע, והוא עדיין מציג את ה-Toast. קו צהוב מתחת לטקסט בעברית הוא רק אזהרה, אפשר להתעלם ממנו בינתיים.

3

מוסיפים שורה אופקית עם שתי עמודות

התוצאה הרצויה בסוף הצעדמתחת לכפתור מופיעים שני מלבנים צבעוניים ריקים, זה ליד זה. כל מלבן תופס חצי מרוחב המסך, ושניהם ממלאים את כל הגובה שנשאר.

הדביקו את הקוד הבא אחרי התגית של הכפתור (/>) ולפני השורה האחרונה </LinearLayout>.

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_marginTop="16dp"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FFE0B2"
            android:gravity="center_horizontal"
            android:orientation="vertical"
            android:padding="8dp">

        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#B2DFDB"
            android:gravity="center_horizontal"
            android:orientation="vertical"
            android:padding="8dp">

        </LinearLayout>

    </LinearLayout>
מה כתבנו פה

השורה האופקית: גובה 0dp יחד עם layout_weight="1" פירושו "קח את כל הגובה שנשאר במסך".

כל עמודה: רוחב 0dp יחד עם layout_weight="1". שתיהן עם אותו משקל, ולכן כל אחת מקבלת בדיוק חצי מהרוחב. זו הפיצה מההסבר.

שני הצבעים (#FFE0B2, #B2DFDB) זמניים. הם שם כדי שתראו בעיניים איפה כל עמודה נמצאת.

הריצו ובדקו

מתחת לכפתור רואים שני מלבנים צבעוניים שממלאים את שאר המסך, חצי-חצי.

ניסוי של דקה: בעמודה הראשונה שנו את layout_weight מ-1 ל-2 והריצו. מה קרה לרוחב? החזירו ל-1.

הקבוצות הופיעו בסדר הפוך?

במכשיר שמוגדר בעברית, שורה אופקית מסתדרת מימין לשמאל, ולכן העמודה הראשונה בקוד תופיע מימין. במכשיר באנגלית היא תופיע משמאל. זה תקין.

4

ממלאים את העמודה של קבוצה א'

התוצאה הרצויה בסוף הצעדבעמודה הראשונה מופיעים, מלמעלה למטה: שם הקבוצה, ניקוד 0 גדול, ושלושה כפתורים ברוחב העמודה. העמודה השנייה נשארת ריקה בינתיים.

מצאו את העמודה הראשונה (זו עם הרקע #FFE0B2). בין התגית הפותחת שלה לבין </LinearLayout> שסוגר אותה יש שורה ריקה. הדביקו שם את הקוד הבא, ושנו את "הנשרים" לשם הקבוצה שלכם.

            <TextView
                android:id="@+id/tvNameA"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="הנשרים"
                android:textSize="20sp" />

            <TextView
                android:id="@+id/tvScoreA"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:layout_marginBottom="16dp"
                android:text="0"
                android:textSize="64sp" />

            <Button
                android:id="@+id/btnA3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="+3" />

            <Button
                android:id="@+id/btnA2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="+2" />

            <Button
                android:id="@+id/btnA1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="+1" />
מה כתבנו פה

העמודה היא LinearLayout אנכי, ולכן חמשת הרכיבים מסתדרים אחד מתחת לשני. ה-gravity="center_horizontal" שכתבנו על העמודה בצעד 3 ממרכז את השם ואת הניקוד.

לניקוד יש layout_marginTop ו-layout_marginBottom: רווח חיצוני מעליו ומתחתיו, כדי שלא יידבק לשם ולכפתורים.

הכפתורים ברוחב match_parent: כל רוחב העמודה (לא כל רוחב המסך, כי ה"הורה" שלהם הוא העמודה).

הריצו ובדקו

בעמודה אחת רואים שם קבוצה, 0 גדול ושלושה כפתורים. הכפתורים עדיין לא עושים כלום.

5

מחברים את הכפתורים של קבוצה א' לקוד

פתחו את app > java > (שם החבילה שלכם) > MainActivity.

חלק ראשון: מצאו את השורה public class MainActivity extends AppCompatActivity {. מיד אחריה, לפני @Override, הוסיפו:

MainActivity.java (בראש המחלקה)
    int scoreA = 0;
    TextView tvScoreA;

חלק שני: בתוך onCreate, אחרי הקוד של כפתור השריקה ולפני הסוגר המסולסל } שסוגר את onCreate, הוסיפו:

MainActivity.java (בסוף onCreate)
        tvScoreA = findViewById(R.id.tvScoreA);

        Button btnA3 = findViewById(R.id.btnA3);
        Button btnA2 = findViewById(R.id.btnA2);
        Button btnA1 = findViewById(R.id.btnA1);

        btnA3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scoreA = scoreA + 3;
                tvScoreA.setText(String.valueOf(scoreA));
            }
        });

        btnA2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scoreA = scoreA + 2;
                tvScoreA.setText(String.valueOf(scoreA));
            }
        });

        btnA1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scoreA = scoreA + 1;
                tvScoreA.setText(String.valueOf(scoreA));
            }
        });

אם TextView או View מסומנים באדום: עמדו על המילה, Alt+Enter, ‏Import class.

מה כתבנו פה

scoreA הוא משתנה שזוכר את הניקוד. הוא מוגדר בראש המחלקה ולא בתוך onCreate, כדי שכל הכפתורים יוכלו לשנות אותו והוא לא "יישכח" בין לחיצה ללחיצה.

findViewById מחבר בין רכיב שציירנו ב-XML (לפי ה-id שלו) לבין משתנה ב-Java.

setOnClickListener מצמיד לכפתור "מאזין". מה שכתוב בתוך הפעולה onClick הוא מה שירוץ בכל לחיצה. כשמקלידים new View.On ובוחרים מההשלמה האוטומטית, Android Studio כותב את כל המעטפת בשבילכם.

בכל לחיצה קורים שני דברים: מעדכנים את המספר בזיכרון, ואז מציגים אותו על המסך. String.valueOf הופך את המספר לטקסט, כי setText צריך לקבל טקסט.

הריצו ובדקו

לחצו ‎+3, ‎+2, ‎+1. הניקוד צריך להיות 6.

6

קבוצה ב': עכשיו אתם

העמודה השנייה היא העתק של הראשונה עם שמות אחרים. בצעו לבד:

  1. ב-XML: העתיקו את חמשת הרכיבים של קבוצה א' אל תוך העמודה השנייה (זו עם #B2DFDB).
  2. שנו בעותק את כל ה-id לפי הטבלה, ואת שם הקבוצה.
  3. ב-Java: הוסיפו scoreB ו-tvScoreB בראש המחלקה, ואת אותו קוד של הכפתורים עם B במקום A.
בקבוצה א'בקבוצה ב'
tvNameAtvNameB
tvScoreAtvScoreB
btnA3, btnA2, btnA1btnB3, btnB2, btnB1
scoreAscoreB
הטעות הנפוצה ביותר בצעד הזה

שוכחים לשנות A ל-B באחד המקומות. אם לחיצה על כפתור של קבוצה ב' מעלה את הניקוד של קבוצה א', חפשו בקוד של קבוצה ב' איפה נשאר A.

נתקעתי: הקוד המלא של קבוצה ב' ב-Java

בראש המחלקה:

    int scoreB = 0;
    TextView tvScoreB;

בסוף onCreate:

        tvScoreB = findViewById(R.id.tvScoreB);

        Button btnB3 = findViewById(R.id.btnB3);
        Button btnB2 = findViewById(R.id.btnB2);
        Button btnB1 = findViewById(R.id.btnB1);

        btnB3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scoreB = scoreB + 3;
                tvScoreB.setText(String.valueOf(scoreB));
            }
        });

        btnB2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scoreB = scoreB + 2;
                tvScoreB.setText(String.valueOf(scoreB));
            }
        });

        btnB1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scoreB = scoreB + 1;
                tvScoreB.setText(String.valueOf(scoreB));
            }
        });
הריצו ובדקו

כל קבוצה סופרת בנפרד. לחיצות על קבוצה ב' לא משנות את הניקוד של קבוצה א'.

7

כפתור איפוס, והמאפיינים של כפתור

צבע: ב-colors.xml הוסיפו לפני </resources>:

res/values/colors.xml
    <color name="btn_reset">#C62828</color>

הכפתור: ב-activity_main.xml, אחרי ה-</LinearLayout> שסוגר את השורה האופקית ולפני ה-</LinearLayout> האחרון בקובץ:

    <Button
        android:id="@+id/btnReset"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"
        android:backgroundTint="@color/btn_reset"
        android:paddingStart="32dp"
        android:paddingEnd="32dp"
        android:text="איפוס"
        android:textColor="#FFFFFF"
        android:textSize="18sp" />

הקוד: בסוף onCreate ב-MainActivity.java:

        Button btnReset = findViewById(R.id.btnReset);
        btnReset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scoreA = 0;
                scoreB = 0;
                tvScoreA.setText("0");
                tvScoreB.setText("0");
            }
        });
scoreB או tvScoreB מסומנים באדום?

אל תמחקו את השורה ואל תמשיכו הלאה. זו תקלה שכדאי להבין לבד:

  1. עמדו עם העכבר על המילה האדומה וקראו את ההודעה. כתוב שם Cannot resolve symbol, כלומר "אני לא מכיר את השם הזה".
  2. שאלו את עצמכם: למה scoreA לא אדום ו-scoreB כן? מה נעשה ל-scoreA שלא נעשה ל-scoreB?
  3. תקנו, וודאו שהאדום נעלם.
רמז

אין הגדרה של המשתנה. ב-Java אי אפשר להשתמש במשתנה לפני שהגדירו אותו. חפשו בראש המחלקה איפה מוגדרים scoreA ו-tvScoreA, והשלימו לידם את מה שחסר לקבוצה ב'. זה חלק מצעד 6.

מאפיינים (properties) של כפתור שכדאי להכיר

מאפייןמה הוא קובע
android:textהטקסט שעל הכפתור
android:textSizeגודל הטקסט, ביחידות sp
android:textColorצבע הטקסט
android:backgroundTintצבע הרקע של הכפתור
android:paddingStart / paddingEndרווח פנימי בצדדים, מרחיב את הכפתור
android:enabledfalse הופך את הכפתור לאפור ולא לחיץ
למה backgroundTint ולא background

בפרויקטים חדשים הכפתור מגיע עם עיצוב מוכן (Material). אם תכתבו android:background עם צבע, ברוב המקרים לא יקרה כלום. הדרך לשנות צבע של כפתור היא backgroundTint.

בדיקת סיום של הפרויקט
  • שתי קבוצות זו ליד זו, כל אחת עם שם, ניקוד ושלושה כפתורים.
  • כל כפתור מוסיף את המספר הנכון לקבוצה הנכונה.
  • איפוס מחזיר את שתי הקבוצות ל-0.
  • כפתור האיפוס אדום, עם טקסט לבן, באמצע המסך למטה.
חלק 4

נקודת בדיקה

קראו למורה. תתבקשו להסביר בעל-פה את שלושת הדברים הבאים. הכינו את התשובות לפני כן, ונסו כל דבר באפליקציה שלכם.

א. באג לתיקון

תלמיד כתב את הקוד הבא. האפליקציה נבנית בלי שגיאות, אבל קורסת ברגע שלוחצים על הכפתור.

btnA1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        scoreA = scoreA + 1;
        tvScoreA.setText(scoreA);
    }
});

החליפו זמנית את הקוד שלכם בקוד הזה, הריצו ולחצו. פתחו את חלון Logcat בתחתית Android Studio וחפשו את השורות האדומות. מה שם השגיאה? מה לא בסדר בקוד, ואיך מתקנים? אל תשכחו להחזיר את הקוד התקין.

ב. מה יקרה אם

נחשו קודם, ורק אחר כך נסו:

  1. מוחקים את השורה android:layout_weight="1" מהעמודה של קבוצה ב' בלבד. מה רואים על המסך, ולמה?
  2. משנים את layout_weight של עמודה א' ל-3 ומשאירים את ב' על 1. איזה חלק מרוחב המסך מקבלת כל קבוצה?

ג. במילים שלכם

מה ההבדל בין gravity ל-layout_gravity? הראו בקוד שלכם מקום אחד שבו השתמשנו בכל אחד מהם.

חלק 5

הרחבות

כאן אין צעד-צעד. יש דרישה, הגדרת הצלחה ורמז. כל מה שצריך כבר מופיע במדריך הזה או בשני המדריכים הקודמים.

הרחבה 1: עיצוב הקבוצות10 נק'

כרגע צבעי העמודות כתובים ישירות בקוד וכל הכפתורים נראים אותו דבר. תנו לכל קבוצה 'זהות':

הצלחה: אין אף # בקובץ activity_main.xml, והמסך נראה כמו לוח של שתי קבוצות שונות.

רמז

רווח בין שתי קופסאות שכנות הוא margin. נסו layout_marginEnd על העמודה הראשונה.

הרחבה 2: תיקון טעות15 נק'

השופט לחץ בטעות. הוסיפו לכל קבוצה כפתור "‎-1" שמוריד נקודה אחת.

הצלחה: מ-2 לוחצים ‎-1 שלוש פעמים. רואים 1, אחר כך 0, ובפעם השלישית נשאר 0 ומופיעה ההודעה.

רמז

לפני שמורידים, בודקים עם if אם הניקוד גדול מ-0.

הרחבה 3: סיום משחק15 נק'

הוסיפו כפתור "סיום משחק" שיושב ליד כפתור האיפוס, באותה שורה.

הצלחה: אחרי "סיום משחק" אי אפשר לשנות את הניקוד עד שלוחצים "איפוס".

רמז

שני כפתורים זה ליד זה, בתוך מסך אנכי: צריך קופסה חדשה. וב-Java, לכל כפתור יש פעולה setEnabled(false).

חלק 6

מסלול מתקדם

פתוח לכל מי שסיים את הפרויקט ואת נקודת הבדיקה. כאן אין צעדים ואין רמזים. יש יעד וקישור לתיעוד הרשמי, ואתם לומדים לבד. על כל משימה תצטרכו להסביר למורה מה עשיתם ולמה זה עובד.

מתקדם 1: אותו מסך, בלי קינון+10

קינון של קופסה בתוך קופסה עובד, אבל במסכים מורכבים הוא נהיה מסורבל ואיטי. ConstraintLayout פותר את זה: כל הרכיבים יושבים בקופסה אחת, וכל רכיב "נקשר" לשכנים שלו.

למורה: מתי הייתם בוחרים ב-LinearLayout ומתי ב-ConstraintLayout?

תיעוד: Build a responsive UI with ConstraintLayout

מתקדם 2: מה קורה כשמסובבים את המכשיר+10

צברו כמה נקודות וסובבו את המכשיר לרוחב. תגלו שתי בעיות: חלק מהמסך נחתך, והניקוד חוזר ל-0.

למורה: מה בדיוק קורה ל-Activity ברגע הסיבוב? (זה הנושא של המדריך הבא, אתם מקדימים את הכיתה.)

תיעוד: Handle configuration changes

מתקדם 3: קוד בלי שכפולים+10

בפתרון הבסיסי יש שישה כפתורים כמעט זהים ב-XML ושישה קטעי קוד כמעט זהים ב-Java. מתכנת מקצועי לא משאיר את זה כך.

למורה: אם מחר נרצה להוסיף קבוצה שלישית, כמה שורות צריך לשנות אצלכם, וכמה בפתרון הבסיסי?

תיעוד: Styles and themes

חלק 7

הניקוד שלי

סמנו מה שהמורה אישר. הסימון נשמר בדפדפן שלכם בלבד.

0 נקודות (100 בלי בונוס, 130 עם בונוס)
סיימתם

הראו למורה את האפליקציה רצה, ואז הגישו כרגיל: File ← Export ← Export to Zip File, והעלאה ל-Classroom.