ניווט באמצעות תנועות וממשק מקצה לקצה

1. מבוא

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

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

ה-Codelab הזה נועד ללמד אתכם איך להשתמש ב-insets כדי למנוע התנגשויות בין תנועות. בנוסף, במעבדת התכנות הזו נלמד איך להשתמש ב-Gesture Exclusion API עבור אמצעי בקרה, כמו ידיות גרירה, שצריכים להיות ממוקמים באזורי המחוות.

מה תלמדו

  • איך משתמשים במאזינים מוטבעים בתצוגות
  • איך משתמשים ב-Gesture Exclusion API
  • איך מצב ההסתרה האוטומטית מתנהג כשהתנועות מופעלות

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

מה תפַתחו

הנגן האוניברסלי למוזיקה ב-Android‏ (UAMP) הוא דוגמה לאפליקציית נגן מוזיקה ל-Android שנכתבה ב-Kotlin. תגדירו את UAMP לניווט באמצעות תנועות.

  • שימוש בתוספות כדי להרחיק את אמצעי הבקרה מאזורי התנועות
  • שימוש ב-Gesture Exclusion API כדי לבטל את תנועת החזרה עבור אמצעי בקרה שמתנגשים
  • שימוש בגרסאות ה-build כדי לבדוק שינויים בהתנהגות של מצב ההפעלה עם ניווט באמצעות תנועות

מה תצטרכו

  • מכשיר או אמולטור עם Android מגרסה 10 ואילך
  • Android Studio

‫2. סקירה כללית של האפליקציה

ה-Universal Android Music Player ‏ (UAMP) הוא אפליקציית נגן מוזיקה לדוגמה ל-Android שנכתבה ב-Kotlin. הוא תומך בתכונות שכוללות הפעלה ברקע, טיפול בהרשאת אודיו, שילוב עם Assistant ומגוון פלטפורמות כמו Wear,‏ TV ו-Auto.

איור 1: תרשים זרימה ב-UAMP

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

‫3. להגדרה

כדי להוריד את האפליקציה לדוגמה, משכפלים את המאגר מ-GitHub ועוברים להסתעפות starter:

$  git clone https://github.com/googlecodelabs/android-gestural-navigation/

אפשר גם להוריד את המאגר כקובץ ZIP, לבטל את הדחיסה שלו ולפתוח אותו ב-Android Studio.

כך עושים את זה:

  1. פותחים את האפליקציה ב-Android Studio ובוחרים באפשרות לבנייה.
  2. יוצרים מכשיר וירטואלי חדש ובוחרים באפשרות API level 29 (רמת API‏ 29). אפשר גם לחבר מכשיר אמיתי עם רמת API‏ 29 ומעלה.
  3. מפעילים את האפליקציה. השירים שמוצגים ברשימה מקובצים לפי האפשרויות מומלצים ואלבומים.
  4. לוחצים על מומלצים ובוחרים שיר מתוך רשימת השירים.
  5. האפליקציה מתחילה להפעיל את השיר.

הפעלת ניווט באמצעות תנועות

אם מריצים מופע חדש של אמולטור עם רמת API‏ 29, יכול להיות שהניווט באמצעות מחוות לא יופעל כברירת מחדל. כדי להפעיל את הניווט באמצעות תנועות, בוחרים באפשרות הגדרות המערכת > מערכת > ניווט במערכת > ניווט באמצעות תנועות.

הפעלת האפליקציה באמצעות ניווט בתנועות

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

4. תצוגה מקצה לקצה

מה זה תצוגה מקצה לקצה?

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

ציור מאחורי סרגל הניווט

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

כדי לשנות את הצבע של סרגל הניווט וסרגל הסטטוס, מבצעים את השלבים הבאים:

  1. סרגל הניווט: פותחים את res/values-29/styles.xml ומגדירים את navigationBarColor לערך color/transparent.
  2. שורת סטטוס: מגדירים את statusBarColor ל-color/transparent.

כדאי לעיין בדוגמת הקוד הבאה של res/values-29/styles.xml:

<!-- change navigation bar color -->
<item name="android:navigationBarColor">
    @android:color/transparent
</item>

<!-- change status bar color -->
<item name="android:statusBarColor">
    @android:color/transparent
</item>

דגלים של הרשאות גישה לממשק המשתמש של המערכת

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

  1. פותחים את המחלקה MainActivity.kt ומחפשים את ה-method‏ onCreate(). מקבלים מופע של fragmentContainer.
  2. מגדירים את הערך content.systemUiVisibility:

כדאי לעיין בדוגמת הקוד הבאה של MainActivity.kt:

  val content: FrameLayout = findViewById(R.id.fragmentContainer)
  content.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

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

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

  1. עוברים להגדרות המערכת, חוזרים למצב ניווט ב-3 לחצנים וחוזרים לאפליקציה.
  2. מוודאים שקשה עוד יותר להשתמש באמצעי הבקרה עם סרגל הניווט עם שלושת הלחצנים: שימו לב שהלחצן SeekBar מוסתר מאחורי סרגל הניווט, ושהלחצן הפעלה/השהיה מכוסה ברובו על ידי סרגל הניווט.
  3. כדאי לחקור ולנסות קצת. אחרי שמסיימים, עוברים להגדרות המערכת וחוזרים לניווט באמצעות תנועות:

741ef664e9be5e7f.gif

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

5. מוטמעים

WindowInsets מציינים לאפליקציה איפה ממשק המשתמש של המערכת מופיע מעל התוכן, וגם באילו אזורים במסך מחוות המערכת מקבלות עדיפות על פני מחוות בתוך האפליקציה. התוספים מוצגים באמצעות המחלקה WindowInsets והמחלקה WindowInsetsCompat ב-Jetpack. מומלץ מאוד להשתמש ב- WindowInsetsCompat כדי להבטיח התנהגות עקבית בכל רמות ה-API.

שוליים פנימיים של המערכת ושוליים פנימיים של המערכת שחובה להשתמש בהם

ממשקי ה-API הבאים של שוליים פנימיים הם הסוגים הנפוצים ביותר של שוליים פנימיים:

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

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

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

  1. קבלת מופע של playerLayout ממופע האובייקט view.
  2. מוסיפים OnApplyWindowInsetsListener לplayerView.
  3. להרחיק את התצוגה מאזור התנועות: מוצאים את ערך השוליים של המערכת עבור החלק התחתון ומגדילים את הריווח הפנימי של התצוגה בסכום הזה. כדי לעדכן את השוליים הפנימיים של התצוגה בהתאם, מוסיפים ל[ערך שמשויך לשוליים הפנימיים התחתונים של האפליקציה] את [הערך שמשויך לשוליים הפנימיים התחתונים של המערכת].

כדאי לעיין בדוגמת הקוד הבאה של NowPlayingFragment.kt:

playerView = view.findViewById(R.id.playerLayout)
playerView.setOnApplyWindowInsetsListener { view, insets ->
   view.updatePadding(
      bottom = insets.systemWindowInsetBottom + view.paddingBottom
   )
   insets
}
  1. מפעילים את האפליקציה ובוחרים שיר. שימו לב שלא נראה שום שינוי בכפתורי הנגן. אם מוסיפים נקודת עצירה ומריצים את האפליקציה בניפוי באגים, רואים שהמאזין לא נקרא.
  2. כדי לפתור את הבעיה, צריך לעבור אל FragmentContainerView, שפותר את הבעיה באופן אוטומטי. פותחים את activity_main.xml ומשנים את FrameLayout ל- FragmentContainerView.

כדאי לעיין בדוגמת הקוד הבאה של activity_main.xml:

<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragmentContainer"
    tools:context="com.example.android.uamp.MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  1. מפעילים שוב את האפליקציה ועוברים למסך הנגן. כפתורי הנגן בתחתית המסך מוזזים מאזור התנועות בתחתית המסך.

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

שמירה על הריווח הפנימי והשוליים הנוכחיים

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

הסיבה לכך היא שהאפליקציה מפעילה את requestApplyInsets() בכל פעם שהפעילות מתחילה. גם בלי הקריאה הזו, אפשר לשלוח את WindowInsets כמה פעמים בכל שלב במהלך מחזור החיים של צפייה.

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

כדי לפתור את הבעיה, מבצעים את השלבים הבאים:

  1. מתעדים את ערך הריווח הראשוני של התצוגה. יוצרים משתנה חדש ומאחסנים בו את ערך הריווח הראשוני של התצוגה playerView, ממש לפני קוד ה-listener.

כדאי לעיין בדוגמת הקוד הבאה של NowPlayingFragment.kt:

   val initialPadding = playerView.paddingBottom
  1. משתמשים בערך ההתחלתי הזה כדי לעדכן את שוליים הפנימיים התחתונים של התצוגה, וכך נמנעים משימוש בערך הנוכחי של השוליים הפנימיים התחתונים של האפליקציה.

כדאי לעיין בדוגמת הקוד הבאה של NowPlayingFragment.kt:

   playerView.setOnApplyWindowInsetsListener { view, insets ->
            view.updatePadding(bottom = insets.systemWindowInsetBottom + initialPadding)
            insets
        }
  1. מפעילים את האפליקציה שוב. מעבר בין אפליקציות וחזרה למסך הבית. כשחוזרים לאפליקציה, כפתורי הנגן נמצאים מעל אזור המחוות.

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

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

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

  1. פתיחת fragment_nowplaying.xml. עוברים לתצוגת העיצוב ובוחרים באפשרות SeekBar בחלק התחתון:

74918dec3926293f.png

  1. עוברים לתצוגת הקוד.
  2. כדי להזיז את SeekBar לחלק העליון של playerLayout, משנים את layout_constraintTop_toBottomOf של SeekBar ל-parent.
  3. כדי להצמיד פריטים אחרים ב-playerView לחלק התחתון של SeekBar, משנים את הערך של layout_constraintTop_toTopOf מ-parent ל-@+id/seekBar ב-media_button, ב-title וב-position.

כדאי לעיין בדוגמת הקוד הבאה של fragment_nowplaying.xml:

<androidx.constraintlayout.widget.ConstraintLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:padding="8dp"
   android:layout_gravity="bottom"
   android:background="@drawable/media_overlay_background"
   android:id="@+id/playerLayout">

   <ImageButton
       android:id="@+id/media_button"
       android:layout_width="@dimen/exo_media_button_width"
       android:layout_height="@dimen/exo_media_button_height"
       android:background="?attr/selectableItemBackground"
       android:scaleType="centerInside"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:srcCompat="@drawable/ic_play_arrow_black_24dp"
       tools:ignore="ContentDescription" />

   <TextView
       android:id="@+id/title"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginTop="8dp"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Title"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:layout_constraintLeft_toRightOf="@id/media_button"
       app:layout_constraintRight_toLeftOf="@id/position"
       tools:text="Song Title" />

   <TextView
       android:id="@+id/subtitle"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Subtitle"
       app:layout_constraintTop_toBottomOf="@+id/title"
       app:layout_constraintLeft_toRightOf="@id/media_button"
       app:layout_constraintRight_toLeftOf="@id/position"
       tools:text="Artist" />

   <TextView
       android:id="@+id/position"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginTop="8dp"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Title"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:layout_constraintRight_toRightOf="parent"
       tools:text="0:00" />

   <TextView
       android:id="@+id/duration"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Subtitle"
       app:layout_constraintTop_toBottomOf="@id/position"
       app:layout_constraintRight_toRightOf="parent"
       tools:text="0:00" />

   <SeekBar
       android:id="@+id/seekBar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  1. מריצים את האפליקציה ומקיימים אינטראקציה עם הנגן ועם סרגל ההתקדמות.

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

6. Gesture Exclusion API

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

e6d98e94dcf83dde.png

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

שימוש ב-Gesture Exclusion API

כדי ליצור אזור החרגה של תנועות, קוראים ל-setSystemGestureExclusionRects() בתצוגה עם רשימה של אובייקטים מסוג rect. אובייקטים מסוג rect ממופים לקואורדינטות של אזורי המלבן שהוחרגו. הקריאה הזו צריכה להתבצע בשיטות onLayout() או onDraw() של התצוגה. כדי לעשות זאת:

  1. יוצרים חבילה חדשה בשם view.
  2. כדי לשלוח קריאה ל-API הזה, יוצרים מחלקה חדשה בשם MySeekBar ומרחיבים את AppCompatSeekBar.

כדאי לעיין בדוגמת הקוד הבאה של MySeekBar.kt:

class MySeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = android.R.attr.seekBarStyle
) : androidx.appcompat.widget.AppCompatSeekBar(context, attrs, defStyle) {

}
  1. יוצרים שיטה חדשה בשם updateGestureExclusion().

כדאי לעיין בדוגמת הקוד הבאה של MySeekBar.kt:

private fun updateGestureExclusion() {

}
  1. מוסיפים בדיקה כדי לדלג על הקריאה הזו ברמת API‏ 28 ומטה.

כדאי לעיין בדוגמת הקוד הבאה של MySeekBar.kt:

private fun updateGestureExclusion() {
        // Skip this call if we're not running on Android 10+
        if (Build.VERSION.SDK_INT < 29) return
}
  1. ממשק Gesture Exclusion API מוגבל ל-200dp, לכן צריך להחריג רק את האגודל של סרגל ההתקדמות. מקבלים עותק של הגבולות של סרגל ההתקדמות ומוסיפים כל אובייקט לרשימה שניתנת לשינוי.

כדאי לעיין בדוגמת הקוד הבאה של MySeekBar.kt:

private val gestureExclusionRects = mutableListOf<Rect>()

private fun updateGestureExclusion() {
    // Skip this call if we're not running on Android 10+
    if (Build.VERSION.SDK_INT < 29) return

    thumb?.also { t ->
        gestureExclusionRects += t.copyBounds()
    }
}
  1. להתקשר אל systemGestureExclusionRects() עם רשימות gestureExclusionRects שיוצרים.

כדאי לעיין בדוגמת הקוד הבאה של MySeekBar.kt:

private val gestureExclusionRects = mutableListOf<Rect>()

private fun updateGestureExclusion() {
    // Skip this call if we're not running on Android 10+
    if (Build.VERSION.SDK_INT < 29) return

    thumb?.also { t ->
        gestureExclusionRects += t.copyBounds()
    }
    // Finally pass our updated list of rectangles to the system
    systemGestureExclusionRects = gestureExclusionRects
}
  1. מבצעים קריאה ל-method‏ updateGestureExclusion() מ-onDraw() או מ-onLayout(). להחליף את onDraw() ולהוסיף שיחה ל-updateGestureExclusion.

כדאי לעיין בדוגמת הקוד הבאה של MySeekBar.kt:

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    updateGestureExclusion()
}
  1. צריך לעדכן את ההפניות ל-SeekBar. כדי להתחיל, פותחים את fragment_nowplaying.xml.
  2. שינוי של SeekBar ל-com.example.android.uamp.view.MySeekBar.

כדאי לעיין בדוגמת הקוד הבאה של fragment_nowplaying.xml:

<com.example.android.uamp.view.MySeekBar
    android:id="@+id/seekBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="parent" />
  1. כדי לעדכן את ההפניות ל-SeekBar ב-NowPlayingFragment.kt, פותחים את NowPlayingFragment.kt ומשנים את הסוג של positionSeekBar ל-MySeekBar. כדי להתאים את סוג המשתנה, משנים את SeekBar הגנריקה של הקריאה findViewById ל-MySeekBar.

כדאי לעיין בדוגמת הקוד הבאה של NowPlayingFragment.kt:

val positionSeekBar: MySeekBar = view.findViewById<MySeekBar>(
     R.id.seekBar
).apply { progress = 0 }
  1. מריצים את האפליקציה ומבצעים אינטראקציה עם SeekBar. אם עדיין יש התנגשויות בין מחוות, אפשר להתנסות ולשנות את הגבולות של האגודל בMySeekBar. חשוב להיזהר ולא ליצור אזור להחרגת מחוות גדול יותר מהנדרש, כי זה מגביל קריאות פוטנציאליות אחרות להחרגת מחוות ויוצר התנהגות לא עקבית עבור המשתמש.

7. מזל טוב

מעולה! למדתם איך למנוע התנגשויות עם תנועות מערכת ואיך לפתור אותן.

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

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

חומרי לימוד נוספים

מאמרי עזרה