1. مقدمة
في الإصدار 10 من نظام التشغيل Android أو الإصدارات الأحدث، تتوفّر إيماءات التنقّل كوضع جديد. يتيح ذلك لتطبيقك استخدام الشاشة بأكملها وتقديم تجربة عرض أكثر غامرة. عندما يمرّر المستخدم سريعًا للأعلى من الحافة السفلية للشاشة، يتم نقله إلى شاشة Android الرئيسية. عندما يمرّر المستخدم سريعًا من الحافة اليسرى أو اليمنى إلى الداخل، يتم نقله إلى الشاشة السابقة.
باستخدام هاتين الإيماءتين، يمكن لتطبيقك الاستفادة من مساحة الشاشة في أسفلها. ومع ذلك، إذا كان تطبيقك يستخدم إيماءات أو يتضمّن عناصر تحكّم في مناطق إيماءات نظام التشغيل، قد يحدث تعارض مع الإيماءات على مستوى النظام.
يهدف هذا الدرس التطبيقي إلى تعليمك كيفية استخدام المساحات الداخلية لتجنُّب تعارض الإيماءات. بالإضافة إلى ذلك، يهدف هذا الدرس التطبيقي حول الترميز إلى تعليمك كيفية استخدام Gesture Exclusion API لعناصر التحكّم، مثل مقابض السحب، التي يجب أن تكون في مناطق الإيماءات.
ما ستتعلمه
- كيفية استخدام أدوات معالجة عمليات الإدخال في طرق العرض
- كيفية استخدام Gesture Exclusion API
- طريقة عمل الوضع الغامر عندما تكون الإيماءات نشطة
يهدف هذا الدرس التطبيقي حول الترميز إلى جعل تطبيقك متوافقًا مع "إيماءات النظام". يتم تجاهل المفاهيم ومجموعات الرموز غير ذات الصلة وتقديمها لك لنسخها ولصقها.
ما ستنشئه
Universal Android Music Player (UAMP) هو مثال على تطبيق مشغّل موسيقى لنظام Android مكتوب بلغة Kotlin. عليك إعداد UAMP للتنقّل بالإيماءات.
- استخدام الحواف الداخلية لإبعاد عناصر التحكّم عن مناطق الإيماءات
- استخدام Gesture Exclusion API لإيقاف الإيماءة الرجوع لعناصر التحكّم المتعارضة
- استخدام إصداراتك التجريبية لاستكشاف تغييرات سلوك الوضع الغامر مع ميزة "التنقّل بالإيماءات"
المتطلبات
- جهاز أو محاكي يعمل بالإصدار 10 من نظام التشغيل Android أو إصدار أحدث
- استوديو Android
2. نظرة عامة على التطبيق
Universal Android Music Player (UAMP) هو تطبيق نموذجي لتشغيل الموسيقى على Android مكتوب بلغة Kotlin. يتوافق مع ميزات تشمل التشغيل في الخلفية، والتعامل مع أولويّة الصوت، والتكامل مع "مساعد Google"، والعديد من المنصات، مثل Wear وTV وAuto.
|
|
|
الشكل 1: مسار في "منصة Google الإعلانية الموحّدة"
تحمّل UAMP فهرسًا موسيقيًا من خادم بعيد وتسمح للمستخدم بتصفّح الألبومات والأغاني. ينقر المستخدم على أغنية ويتم تشغيلها من خلال مكبّرات صوت أو سماعات رأس متصلة. التطبيق غير مصمّم للعمل مع "إيماءات النظام". لذلك، عند تشغيل UAMP على جهاز يعمل بالإصدار 10 من نظام التشغيل Android أو إصدار أحدث، ستواجه بعض المشاكل في البداية.
3- طريقة الإعداد
للحصول على نموذج التطبيق، استنسِخ المستودع من GitHub وانتقِل إلى فرع starter:
$ git clone https://github.com/googlecodelabs/android-gestural-navigation/
بدلاً من ذلك، يمكنك تنزيل المستودع كملف مضغوط وفك ضغطه وفتحه في استوديو Android.
أكمِل الخطوات التالية:
- افتح التطبيق وأنشئه في "استوديو Android".
- أنشئ جهازًا افتراضيًا جديدًا واختَر مستوى واجهة برمجة التطبيقات 29. بدلاً من ذلك، يمكنك توصيل جهاز حقيقي يعمل بالمستوى 29 من واجهة برمجة التطبيقات أو مستوى أعلى.
- شغِّل التطبيق. ستظهر لك قائمة تصنّف الأغاني ضمن الخيارَين مقترَحة وألبومات.
- انقر على مقترَحة واختَر أغنية من قائمة الأغاني.
- يبدأ التطبيق تشغيل الأغنية.
تفعيل ميزة "التنقّل بالإيماءات"
إذا شغّلت مثيلاً جديدًا للمحاكي بالمستوى 29 من واجهة برمجة التطبيقات، قد لا يتم تفعيل ميزة "التنقّل بالإيماءات" تلقائيًا. لتفعيل ميزة "التنقل بالإيماءات"، اختَر إعدادات النظام > النظام > التنقل في النظام > التنقل بالإيماءات.
تشغيل التطبيق باستخدام ميزة "التنقّل بالإيماءات"
إذا شغّلت التطبيق مع تفعيل ميزة "التنقّل بالإيماءات" وبدأت تشغيل أغنية، قد تلاحظ أنّ عناصر التحكّم في المشغّل قريبة جدًا من مناطق الإيماءات "الرجوع" و"الصفحة الرئيسية".
4. العرض حتى حافة الشاشة
ما المقصود بالعرض من الحافة إلى الحافة؟
يمكن للتطبيقات التي تعمل بالإصدار 10 من نظام التشغيل Android أو الإصدارات الأحدث أن تقدّم تجربة ملء الشاشة من الحافة إلى الحافة، بغض النظر عمّا إذا كانت الإيماءات أو الأزرار مفعّلة للتنقّل. لتقديم تجربة من الحافة إلى الحافة، يجب أن يتم عرض تطبيقاتك خلف شريطي التنقّل والحالة الشفافَين.
الرسم خلف شريط التنقّل
لكي يعرض تطبيقك المحتوى أسفل شريط التنقّل، يجب أولاً جعل خلفية شريط التنقّل شفافة. بعد ذلك، عليك جعل شريط الحالة شفافًا. يسمح ذلك لتطبيقك بعرض التطبيق على كامل ارتفاع الشاشة.
لتغيير لون شريط التنقّل وشريط الحالة، اتّبِع الخطوات التالية:
- شريط التنقّل: افتح
res/values-29/styles.xmlواضبطnavigationBarColorعلىcolor/transparent. - شريط الحالة: اضبط
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>
علامات إذن الوصول إلى واجهة مستخدم النظام
يجب أيضًا ضبط علامات إذن الوصول إلى واجهة مستخدم النظام لإخبار النظام بتنسيق التطبيق أسفل أشرطة النظام. تتيح واجهات برمجة التطبيقات systemUiVisibility في الفئة View ضبط مجموعة متنوعة من العلامات. اتّبِع الخطوات التالية:
- افتح الفئة
MainActivity.ktوابحث عن الطريقةonCreate(). احصل على مثيل منfragmentContainer. - اضبط ما يلي على
content.systemUiVisibility:
View.SYSTEM_UI_FLAG_LAYOUT_STABLEView.SYSTEM_UI_FLAG_LAYOUT_FULLSCREENView.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
راجِع عينة التعليمات البرمجية التالية الخاصة بـ 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
عند ضبط هذين العلامتَين معًا، فإنّك تخبر النظام بأنّك تريد عرض تطبيقك بملء الشاشة كما لو لم يكن هناك شريطا التنقّل والحالة. اتّبِع الخطوات التالية:
- شغِّل التطبيق وانتقِل إلى شاشة المشغّل، ثم اختَر أغنية لتشغيلها.
- تأكَّد من أنّ عناصر التحكّم في المشغّل تظهر تحت شريط التنقّل، ما يصعّب الوصول إليها:
|
|
- انتقِل إلى إعدادات النظام، ثم بدِّل إلى وضع التنقّل باستخدام ثلاثة أزرار، وارجع إلى التطبيق.
- تأكَّد من أنّ عناصر التحكّم أصبحت أكثر صعوبة في الاستخدام مع شريط التنقّل الذي يتضمّن ثلاثة أزرار: لاحظ أنّ
SeekBarمخفي خلف شريط التنقّل وأنّ شريط التنقّل يغطّي معظم زر تشغيل/إيقاف مؤقت. - استكشِف وجرِّب بعض الأفكار. بعد الانتهاء، انتقِل إلى إعدادات النظام وعُد إلى "التنقل بالإيماءات" باتّباع الخطوات التالية:

يرسم التطبيق الآن من الحافة إلى الحافة، ولكن هناك مشاكل في سهولة الاستخدام وعناصر تحكّم في التطبيق تتعارض وتتداخل، ويجب حلّ هذه المشاكل.
5- المساحات الداخلية
WindowInsets لتحديد موضع ظهور واجهة مستخدم النظام فوق المحتوى، بالإضافة إلى المناطق التي تحظى فيها إيماءات النظام بالأولوية على الإيماءات داخل التطبيق يتم تمثيل اللوحات الداخلية من خلال الفئة WindowInsets والفئة WindowInsetsCompat في Jetpack. ننصحك بشدة باستخدام WindowInsetsCompat للحصول على سلوك متسق في جميع مستويات واجهة برمجة التطبيقات.
فواصل النظام وفواصل النظام الإلزامية
في ما يلي أنواع الإضافات الأكثر شيوعًا:
- فواصل نوافذ النظام: توضّح لك هذه الفواصل موضع عرض واجهة مستخدم النظام فوق تطبيقك. ونناقش كيفية استخدام فواصل النظام لإبعاد عناصر التحكّم عن أشرطة النظام.
- مساحات إدخال إيماءات نظام التشغيل: تعرض جميع مناطق الإيماءات. يمكن أن تؤدي أي عناصر تحكّم بالتمرير السريع داخل التطبيق في هذه المناطق إلى تشغيل "إيماءات النظام" عن طريق الخطأ.
- هوامش إدخال الإيماءات الإلزامية: هي مجموعة فرعية من هوامش إدخال إيماءات نظام التشغيل ولا يمكن تجاهلها. توضّح لك هذه المناطق الأماكن التي تحظى فيها إيماءات النظام دائمًا بالأولوية على الإيماءات داخل التطبيق.
استخدام الحواف الداخلية لنقل عناصر التحكّم في التطبيقات
بعد أن تعرّفت على المزيد من المعلومات حول واجهات برمجة التطبيقات الخاصة بالحواف الداخلية، يمكنك إصلاح عناصر التحكّم في التطبيق باتّباع الخطوات التالية:
- الحصول على مثيل من
playerLayoutمن مثيل العنصرview - أضِف
OnApplyWindowInsetsListenerإلىplayerView. - إبعاد طريقة العرض عن منطقة الإيماءات: ابحث عن قيمة الحافة الداخلية للنظام في الأسفل وزِدّ مساحة الحشو لطريقة العرض بهذا المقدار. لتعديل مساحة العرض الداخلية وفقًا لذلك، أضِف [القيمة المرتبطة بمساحة العرض الداخلية السفلية للتطبيق] إلى [القيمة المرتبطة بالقيمة السفلية لمساحة العرض الداخلية للنظام].
راجِع عينة التعليمات البرمجية التالية الخاصة بـ NowPlayingFragment.kt:
playerView = view.findViewById(R.id.playerLayout)
playerView.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(
bottom = insets.systemWindowInsetBottom + view.paddingBottom
)
insets
}
- شغِّل التطبيق واختَر أغنية. لاحظ أنّه لن يطرأ أي تغيير على عناصر التحكّم في المشغّل. إذا أضفت نقطة توقّف وشغّلت التطبيق في وضع تصحيح الأخطاء، ستلاحظ أنّه لم يتم استدعاء أداة معالجة الأحداث.
- لحلّ هذه المشكلة، يمكنك التبديل إلى
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"/>
- شغِّل التطبيق مرة أخرى وانتقِل إلى شاشة المشغّل. يتم نقل عناصر التحكّم في المشغّل في أسفل الشاشة بعيدًا عن منطقة الإيماءات في الأسفل.
تعمل عناصر التحكّم في التطبيق الآن مع ميزة "التنقّل بالإيماءات"، ولكنّها تتحرّك أكثر من المتوقّع. يجب حلّ هذه المشكلة.
الحفاظ على المساحة الداخلية والخارجية الحالية
إذا بدّلت إلى تطبيقات أخرى أو انتقلت إلى الشاشة الرئيسية ثم عدت إلى التطبيق بدون إغلاقه، ستلاحظ أنّ عناصر التحكّم في المشغّل تنتقل إلى الأعلى في كل مرة.
ويرجع ذلك إلى أنّ التطبيق يفعّل requestApplyInsets() في كل مرة يبدأ فيها النشاط. حتى بدون هذا الاستدعاء، يمكن إرسال WindowInsets عدة مرات في أي وقت خلال مراحل نشاط العرض.
يعمل InsetListener الحالي على playerView بشكلٍ مثالي في المرة الأولى عند إضافة قيمة مقدار المسافة البادئة السفلية إلى قيمة المسافة البادئة السفلية للتطبيق المُحدّدة في activity_main.xml. ومع ذلك، تستمر المكالمات اللاحقة في إضافة قيمة الجزء السفلي من الحافة الداخلية إلى المساحة المتروكة السفلية للعرض الذي تم تعديله مسبقًا.
لحلّ هذه المشكلة، اتّبِع الخطوات التالية:
- سجِّل قيمة مساحة العرض الأوّلية. أنشئ قيمة جديدة وخزِّن قيمة مساحة العرض الأوّلية
playerView، قبل رمز متتبِّع الأحداث مباشرةً.
راجِع عينة التعليمات البرمجية التالية الخاصة بـ NowPlayingFragment.kt:
val initialPadding = playerView.paddingBottom
- استخدِم هذه القيمة الأولية لتعديل مساحة الحشو السفلية للعرض، ما يتيح لك تجنُّب استخدام قيمة مساحة الحشو السفلية الحالية للتطبيق.
راجِع عينة التعليمات البرمجية التالية الخاصة بـ NowPlayingFragment.kt:
playerView.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(bottom = insets.systemWindowInsetBottom + initialPadding)
insets
}
- شغِّل التطبيق مرة أخرى. التنقّل بين التطبيقات والانتقال إلى الشاشة الرئيسية عند العودة إلى التطبيق، ستظهر عناصر التحكّم في المشغّل فوق منطقة الإيماءات مباشرةً.
إعادة تصميم عناصر التحكّم في التطبيق
شريط البحث في المشغّل قريب جدًا من منطقة الإيماءات في أسفل الشاشة، ما يعني أنّه يمكن للمستخدم تفعيل إيماءة الرجوع إلى الصفحة الرئيسية عن طريق الخطأ عند إكمال تمرير سريع أفقي. وإذا زدت المساحة الفارغة أكثر، قد يؤدي ذلك إلى حلّ المشكلة، ولكن قد يؤدي أيضًا إلى نقل المشغّل إلى موضع أعلى من المطلوب.
يتيح لك استخدام الحواف الداخلية إصلاح تعارضات الإيماءات، ولكن في بعض الأحيان، يمكنك تجنُّب تعارضات الإيماءات تمامًا من خلال إجراء تغييرات بسيطة في التصميم. لإعادة تصميم عناصر التحكّم في المشغّل لتجنُّب تعارض الإيماءات، اتّبِع الخطوات التالية:
- فتح "
fragment_nowplaying.xml" انتقِل إلى "عرض التصميم" وانقر علىSeekBarفي أسفل الصفحة:

- انتقِل إلى "طريقة عرض الرمز".
- لنقل
SeekBarإلى أعلىplayerLayout، غيِّرlayout_constraintTop_toBottomOfفي SeekBar إلىparent. - لتقييد العناصر الأخرى في
playerViewلتكون في أسفلSeekBar، غيِّرlayout_constraintTop_toTopOfمن "العنصر الأصل" إلى@+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>
- شغِّل التطبيق وتفاعَل مع مشغّل الفيديو وشريط التقدّم.
تساهم هذه التغييرات البسيطة في التصميم في تحسين التطبيق بشكل كبير.
6. Gesture Exclusion API
تم إصلاح تعارضات الإيماءات في عناصر التحكّم في المشغّل في منطقة إيماءة الشاشة الرئيسية. يمكن أن يؤدي استخدام إيماءة الرجوع أيضًا إلى حدوث تعارضات مع عناصر التحكّم في التطبيق. توضّح لقطة الشاشة التالية أنّ شريط البحث في مشغّل الفيديو يقع حاليًا في كلّ من منطقتَي إيماءة الرجوع إلى اليمين وإلى اليسار:

تعمل SeekBar على معالجة تعارضات الإيماءات تلقائيًا. ومع ذلك، قد تحتاج إلى استخدام مكوّنات أخرى في واجهة المستخدم تؤدي إلى حدوث تعارضات في الإيماءات. في هذه الحالات، يمكنك استخدام Gesture Exclusion API لإيقاف إيماءة الرجوع جزئيًا.
استخدام Gesture Exclusion API
لإنشاء منطقة استبعاد الإيماءات، استدعِ الدالة setSystemGestureExclusionRects() في طريقة العرض مع قائمة بعناصر rect. ترتبط عناصر rect هذه بإحداثيات مناطق المستطيلات المستبعَدة. يجب إجراء هذه المكالمة في الطريقتَين onLayout() أو onDraw() للعرض. لإجراء ذلك، اتّبِع الخطوات التالية:
- أنشئ حزمة جديدة باسم
view. - لاستخدام واجهة برمجة التطبيقات هذه، أنشئ فئة جديدة باسم
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) {
}
- أنشِئ طريقة جديدة باسم
updateGestureExclusion().
راجِع عينة التعليمات البرمجية التالية الخاصة بـ MySeekBar.kt:
private fun updateGestureExclusion() {
}
- أضِف عملية تحقّق لتخطّي هذا الاستدعاء في المستوى 28 من واجهة برمجة التطبيقات أو المستويات الأقل.
راجِع عينة التعليمات البرمجية التالية الخاصة بـ MySeekBar.kt:
private fun updateGestureExclusion() {
// Skip this call if we're not running on Android 10+
if (Build.VERSION.SDK_INT < 29) return
}
- بما أنّ واجهة برمجة التطبيقات Gesture Exclusion API تفرض حدًا أقصى يبلغ 200 وحدة بكسل مستقلة عن الجهاز، يجب استبعاد إبهام شريط التقدّم فقط. احصل على نسخة من حدود شريط البحث وأضِف كل عنصر إلى قائمة قابلة للتعديل.
راجِع عينة التعليمات البرمجية التالية الخاصة بـ 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()
}
}
- الاتصال بـ
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
}
- استدعِ طريقة
updateGestureExclusion()منonDraw()أوonLayout(). تجاوزonDraw()وإضافة مكالمة إلىupdateGestureExclusion
راجِع عينة التعليمات البرمجية التالية الخاصة بـ MySeekBar.kt:
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
updateGestureExclusion()
}
- يجب تعديل مراجع
SeekBar. للبدء، افتحfragment_nowplaying.xml. - تغيير
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" />
- لتعديل مراجع
SeekBarفيNowPlayingFragment.kt، افتحNowPlayingFragment.ktوغيِّر نوعpositionSeekBarإلىMySeekBar. لمطابقة نوع المتغيّر، غيِّر الأنواع العامةSeekBarلطلبfindViewByIdإلىMySeekBar.
راجِع عينة التعليمات البرمجية التالية الخاصة بـ NowPlayingFragment.kt:
val positionSeekBar: MySeekBar = view.findViewById<MySeekBar>(
R.id.seekBar
).apply { progress = 0 }
- شغِّل التطبيق وتفاعَل مع
SeekBar. إذا استمرّت المشاكل في تعارض الإيماءات، يمكنك تجربة تعديل حدود الإبهام فيMySeekBar. يجب الحرص على عدم إنشاء منطقة استبعاد إيماءات أكبر من اللازم، لأنّ ذلك يحدّ من طلبات استبعاد الإيماءات المحتملة الأخرى، ويؤدي إلى سلوك غير متسق للمستخدم.
7. تهانينا
تهانينا! لقد تعرّفت على كيفية تجنُّب التعارضات مع "إيماءات النظام" وحلّها.
لقد جعلت تطبيقك يستخدم ملء الشاشة عند توسيعه من الحافة إلى الحافة واستخدمت الحواف الداخلية لنقل عناصر التحكّم في التطبيق بعيدًا عن مناطق الإيماءات. تعرّفت أيضًا على كيفية إيقاف إيماءة الرجوع في النظام على عناصر التحكّم في التطبيق.
أصبحت الآن تعرف الخطوات الأساسية المطلوبة لجعل تطبيقاتك تعمل مع "إيماءات النظام".
مواد إضافية
- WindowInsets — أدوات معالجة التنسيقات
- التنقّل بالإيماءات: التنقّل من الحافة إلى الحافة
- التنقّل بالإيماءات: التعامل مع التداخلات المرئية
- التنقّل بالإيماءات: معالجة تعارض الإيماءات
- ضمان التوافق مع ميزة "التنقّل بالإيماءات"




