1. บทนำ
สำหรับ Android เวอร์ชัน 10 ขึ้นไป ระบบจะรองรับท่าทางสัมผัสการนำทางเป็นโหมดใหม่ ซึ่งจะช่วยให้แอปใช้ทั้งหน้าจอและมอบประสบการณ์การแสดงผลที่สมจริงยิ่งขึ้น เมื่อผู้ใช้ปัดขึ้นจากขอบด้านล่างของหน้าจอ ระบบจะนำผู้ใช้ไปยังหน้าจอหลักของ Android เมื่อปัดเข้าจากขอบด้านซ้ายหรือขวา ระบบจะนำผู้ใช้ไปยังหน้าจอก่อนหน้า
ท่าทางสัมผัสทั้ง 2 นี้จะช่วยให้แอปใช้ประโยชน์จากพื้นที่หน้าจอที่ด้านล่างของหน้าจอได้ อย่างไรก็ตาม หากแอปใช้ท่าทางสัมผัสหรือมีการควบคุมในพื้นที่ท่าทางสัมผัสของระบบ แอปอาจขัดแย้งกับท่าทางสัมผัสทั่วทั้งระบบ
Codelab นี้มีจุดมุ่งหมายเพื่อสอนวิธีใช้ระยะขอบเพื่อหลีกเลี่ยงการขัดแย้งของท่าทางสัมผัส นอกจากนี้ Codelab นี้ยังมีจุดมุ่งหมายเพื่อสอนวิธีใช้ Gesture Exclusion API สำหรับการควบคุม เช่น แฮนเดิลการลาก ซึ่งต้องอยู่ในโซนท่าทางสัมผัส
สิ่ง ที่คุณ จะได้เรียนรู้
- วิธีใช้เครื่องฟังที่แทรกในมุมมอง
- วิธีใช้ Gesture Exclusion API
- ลักษณะการทำงานของโหมดสมจริงเมื่อท่าทางสัมผัสทำงานอยู่
Codelab นี้มีจุดมุ่งหมายเพื่อให้แอปของคุณใช้งานร่วมกับท่าทางสัมผัสของระบบได้ เราจะข้ามแนวคิดและบล็อกโค้ดที่ไม่เกี่ยวข้องและให้คุณคัดลอกและวางได้
สิ่งที่คุณจะสร้าง
Universal Android Music Player (UAMP) เป็นตัวอย่างแอปเครื่องเล่นเพลงสำหรับ Android ที่เขียนด้วย Kotlin คุณจะตั้งค่า UAMP สำหรับการไปยังส่วนต่างๆ ด้วยท่าทางสัมผัส
- ใช้ระยะขอบเพื่อย้ายตัวควบคุมออกจากพื้นที่ท่าทางสัมผัส
- ใช้ Gesture Exclusion API เพื่อเลือกไม่ใช้ท่าทางสัมผัสย้อนกลับสำหรับการควบคุมที่ขัดแย้งกัน
- ใช้บิลด์เพื่อสำรวจการเปลี่ยนแปลงลักษณะการทำงานของโหมดสมจริงด้วยการนำทางโดยใช้ท่าทางสัมผัส
สิ่งที่คุณต้องมี
- อุปกรณ์หรือโปรแกรมจำลองที่ใช้ 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 ก็ได้
ทำตามขั้นตอนต่อไปนี้ให้ครบถ้วน
- เปิดและสร้างแอปใน Android Studio
- สร้างอุปกรณ์เสมือนใหม่และเลือก API ระดับ 29 หรือจะเชื่อมต่ออุปกรณ์จริงที่ใช้ API ระดับ 29 ขึ้นไปก็ได้
- เรียกใช้แอป รายการที่คุณเห็นจะจัดกลุ่มเพลงไว้ในส่วนแนะนำและอัลบั้ม
- คลิกแนะนำ แล้วเลือกเพลงจากรายการเพลง
- แอปจะเริ่มเล่นเพลง
เปิดใช้การนำทางด้วยท่าทางสัมผัส
หากเรียกใช้อินสแตนซ์โปรแกรมจำลองใหม่ที่มี API ระดับ 29 ระบบอาจไม่ได้เปิดการนำทางด้วยท่าทางสัมผัสไว้โดยค่าเริ่มต้น หากต้องการเปิดใช้การนำทางด้วยท่าทางสัมผัส ให้เลือกการตั้งค่าระบบ > ระบบ > การนำทางของระบบ > การนำทางด้วยท่าทางสัมผัส
เรียกใช้แอปด้วยการนำทางด้วยท่าทางสัมผัส
หากเรียกใช้แอปโดยเปิดใช้การนำทางด้วยท่าทางสัมผัสและเริ่มเล่นเพลง คุณอาจสังเกตเห็นว่าตัวควบคุมเพลเยอร์อยู่ใกล้กับพื้นที่ท่าทางสัมผัสหน้าแรกและย้อนกลับมาก
4. ไปที่ขอบ
ขอบจรดขอบคืออะไร
แอปที่ทำงานบน Android 10 ขึ้นไปจะมอบประสบการณ์การใช้งานแบบเต็มหน้าจอตั้งแต่ขอบจรดขอบได้ ไม่ว่าคุณจะเปิดใช้ท่าทางสัมผัสหรือปุ่มสำหรับการนำทางหรือไม่ก็ตาม แอปต้องวาดภาพด้านหลังแถบนำทางและแถบสถานะแบบโปร่งใสเพื่อมอบประสบการณ์การใช้งานแบบขอบจรดขอบ
วาดด้านหลังแถบนำทาง
หากต้องการให้แอปแสดงเนื้อหาใต้แถบนำทาง คุณต้องทำให้พื้นหลังของแถบนำทางโปร่งใสก่อน จากนั้นคุณต้องทำให้แถบสถานะโปร่งใส ซึ่งจะช่วยให้แอปแสดงแอปของคุณได้เต็มความสูงของหน้าจอ
หากต้องการเปลี่ยนสีแถบนำทางและแถบสถานะ ให้ทำตามขั้นตอนต่อไปนี้
- แถบนำทาง: เปิด
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>
แฟล็กการแสดง UI ของระบบ
นอกจากนี้ คุณยังต้องตั้งค่าสถานะระดับการเข้าถึง UI ของระบบเพื่อบอกให้ระบบจัดวางแอปไว้ใต้แถบระบบ API ของ systemUiVisibility ในคลาส View ช่วยให้ตั้งค่า Flag ได้หลากหลาย ทำตามขั้นตอนต่อไปนี้
- เปิด
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
เมื่อตั้งค่าแฟล็กเหล่านี้พร้อมกัน คุณจะบอกระบบว่าต้องการให้แอปแสดงแบบเต็มหน้าจอราวกับว่าไม่มีแถบนำทางและแถบสถานะ ทำตามขั้นตอนต่อไปนี้
- เรียกใช้แอปและเลือกเพลงเพื่อเล่นเพื่อไปยังหน้าจอเพลเยอร์
- ตรวจสอบว่าการควบคุมเพลเยอร์อยู่ใต้แถบนำทาง ซึ่งทำให้เข้าถึงได้ยาก
|
|
- ไปที่การตั้งค่าระบบ สลับกลับไปที่โหมดการไปยังส่วนต่างๆ แบบ 3 ปุ่ม แล้วกลับไปที่แอป
- ตรวจสอบว่าแถบนำทางแบบ 3 ปุ่มทำให้ควบคุมได้ยากยิ่งขึ้น: สังเกตว่า
SeekBarซ่อนอยู่หลังแถบนำทาง และเล่น/หยุดชั่วคราวส่วนใหญ่ถูกแถบนำทางบดบัง - ลองสำรวจและทดลองดู หลังจากดำเนินการเสร็จแล้ว ให้ไปที่การตั้งค่าระบบและเปลี่ยนกลับไปใช้การนำทางด้วยท่าทางสัมผัสโดยทำดังนี้

ตอนนี้แอปวาดภาพแบบขอบถึงขอบแล้ว แต่ยังมีปัญหาด้านความสามารถในการใช้งาน การควบคุมแอปที่ขัดแย้งและทับซ้อนกัน ซึ่งต้องได้รับการแก้ไข
5. ข้างใน
WindowInsets จะบอกแอปว่า UI ของระบบปรากฏที่ด้านบนของเนื้อหาที่ใด รวมถึงภูมิภาคใดของหน้าจอที่ท่าทางสัมผัสของระบบมีความสำคัญเหนือกว่าท่าทางสัมผัสในแอป โดยมีคลาส WindowInsets และคลาส WindowInsetsCompat ใน Jetpack เราขอแนะนำเป็นอย่างยิ่งให้ใช้ WindowInsetsCompat เพื่อให้มีลักษณะการทำงานที่สอดคล้องกันใน API ทุกระดับ
การแทรกระบบและการแทรกระบบที่บังคับ
API การแทรกต่อไปนี้เป็นประเภทการแทรกที่ใช้กันมากที่สุด
- ระยะขอบหน้าต่างของระบบ: ระยะขอบเหล่านี้จะบอกตำแหน่งที่ UI ของระบบแสดงเหนือแอปของคุณ เราจะพูดถึงวิธีใช้ระยะขอบของระบบเพื่อย้ายการควบคุมออกจากแถบของระบบ
- การแทรกท่าทางสัมผัสของระบบ: แสดงผลพื้นที่ท่าทางสัมผัสทั้งหมด การควบคุมด้วยการปัดในแอปในภูมิภาคเหล่านี้อาจทําให้ท่าทางสัมผัสของระบบทํางานโดยไม่ตั้งใจ
- ระยะขอบท่าทางสัมผัสที่บังคับ: เป็นส่วนย่อยของระยะขอบท่าทางสัมผัสของระบบและจะลบล้างไม่ได้ ซึ่งจะบอกให้คุณทราบบริเวณของหน้าจอที่ลักษณะการทำงานของท่าทางสัมผัสของระบบจะมีความสำคัญเหนือกว่าท่าทางสัมผัสในแอปเสมอ
ใช้ Inset เพื่อย้ายตัวควบคุมแอป
ตอนนี้คุณทราบข้อมูลเพิ่มเติมเกี่ยวกับ API สำหรับการแทรกแล้ว จึงสามารถแก้ไขการควบคุมแอปได้ตามขั้นตอนต่อไปนี้
- รับอินสแตนซ์ของ
playerLayoutจากอินสแตนซ์ออบเจ็กต์view - เพิ่ม
OnApplyWindowInsetsListenerลงในplayerView - ย้ายมุมมองออกจากพื้นที่ท่าทางสัมผัส: ค้นหาค่าระยะขอบของระบบสำหรับด้านล่างและเพิ่มระยะขอบของมุมมองตามจำนวนดังกล่าว หากต้องการอัปเดตระยะขอบของมุมมองตามนั้น ให้เพิ่ม [ค่าที่เชื่อมโยงกับระยะขอบด้านล่างของแอป] ไปยัง [ค่าที่เชื่อมโยงกับค่าระยะขอบด้านล่างของระบบ]
ดูตัวอย่างโค้ดต่อไปนี้ของ NowPlayingFragment.kt
playerView = view.findViewById(R.id.playerLayout)
playerView.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(
bottom = insets.systemWindowInsetBottom + view.paddingBottom
)
insets
}
- เรียกใช้แอปแล้วเลือกเพลง โปรดสังเกตว่าตัวควบคุมวิดีโอเพลเยอร์จะไม่มีอะไรเปลี่ยนแปลง หากเพิ่มเบรกพอยต์และเรียกใช้แอปในโหมดแก้ไขข้อบกพร่อง คุณจะเห็นว่าระบบไม่ได้เรียกใช้ Listener
- หากต้องการแก้ไขปัญหานี้ ให้เปลี่ยนไปใช้
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 อย่างไรก็ตาม การเรียกครั้งต่อๆ ไปจะยังคงเพิ่มค่าระยะขอบด้านล่างที่แทรกลงในระยะขอบด้านล่างของมุมมองที่อัปเดตแล้ว
หากต้องการแก้ไขปัญหานี้ ให้ทำตามขั้นตอนต่อไปนี้
- บันทึกค่าการเพิ่มพื้นที่โฆษณาของมุมมองเริ่มต้น สร้าง val ใหม่และจัดเก็บค่าการเว้นวรรคมุมมองเริ่มต้นของ
playerViewไว้ก่อนโค้ด Listener
ดูตัวอย่างโค้ดต่อไปนี้ของ NowPlayingFragment.kt
val initialPadding = playerView.paddingBottom
- ใช้ค่าเริ่มต้นนี้เพื่ออัปเดตระยะห่างจากด้านล่างของ View ซึ่งจะช่วยให้คุณหลีกเลี่ยงการใช้ค่าระยะห่างจากด้านล่างปัจจุบันของแอปได้
ดูตัวอย่างโค้ดต่อไปนี้ของ NowPlayingFragment.kt
playerView.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(bottom = insets.systemWindowInsetBottom + initialPadding)
insets
}
- เรียกใช้แอปอีกครั้ง ไปยังบริเวณต่างๆ ระหว่างแอปและไปที่หน้าจอหลัก เมื่อกลับไปที่แอป ตัวควบคุมวิดีโอเพลเยอร์จะอยู่เหนือพื้นที่ท่าทางสัมผัส
ออกแบบการควบคุมแอปใหม่
แถบเลื่อนของเพลเยอร์อยู่ใกล้กับพื้นที่ท่าทางสัมผัสที่ด้านล่างมากเกินไป ซึ่งหมายความว่าผู้ใช้อาจเรียกใช้ท่าทางสัมผัสหน้าแรกโดยไม่ตั้งใจเมื่อปัดในแนวนอนจนเสร็จ หากเพิ่มระยะเว้นมากยิ่งขึ้น ปัญหานี้อาจได้รับการแก้ไข แต่ก็อาจทำให้ผู้เล่นเลื่อนขึ้นสูงกว่าที่ต้องการด้วย
การใช้ระยะขอบช่วยให้คุณแก้ไขความขัดแย้งของท่าทางสัมผัสได้ แต่ในบางครั้งการเปลี่ยนแปลงการออกแบบเล็กๆ น้อยๆ ก็ช่วยหลีกเลี่ยงความขัดแย้งของท่าทางสัมผัสได้ทั้งหมด หากต้องการออกแบบตัวควบคุมวิดีโอเพลเยอร์ใหม่เพื่อหลีกเลี่ยงการขัดแย้งของท่าทางสัมผัส ให้ทำตามขั้นตอนต่อไปนี้
- เปิด
fragment_nowplaying.xmlเปลี่ยนไปเป็นมุมมองการออกแบบ แล้วเลือกSeekBarที่ด้านล่างสุด

- เปลี่ยนเป็นมุมมองโค้ด
- หากต้องการย้าย
SeekBarไปที่ด้านบนของplayerLayoutให้เปลี่ยนlayout_constraintTop_toBottomOfของแถบเลื่อนเป็น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 จะจัดการความขัดแย้งของท่าทางสัมผัสโดยอัตโนมัติ แต่คุณอาจต้องใช้คอมโพเนนต์ UI อื่นๆ ที่ทำให้เกิดการขัดแย้งของท่าทางสัมผัส ในกรณีเหล่านี้ คุณสามารถใช้ Gesture Exclusion API เพื่อเลือกไม่ใช้ท่าทางสัมผัสย้อนกลับบางส่วนได้
ใช้ Gesture Exclusion API
หากต้องการสร้างโซนยกเว้นท่าทางสัมผัส ให้เรียกใช้ setSystemGestureExclusionRects() ในมุมมองของคุณด้วยรายการออบเจ็กต์ rect ออบเจ็กต์ rect เหล่านี้จะแมปกับพิกัดของพื้นที่สี่เหลี่ยมผืนผ้าที่ยกเว้น การเรียกนี้ต้องทำในเมธอด onLayout() หรือ onDraw() ของมุมมอง โดยทำตามขั้นตอนต่อไปนี้
- สร้างแพ็กเกจใหม่ชื่อ
view - หากต้องการเรียกใช้ 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) {
}
- สร้างเมธอดใหม่ชื่อ
updateGestureExclusion()
ดูตัวอย่างโค้ดต่อไปนี้ของ MySeekBar.kt
private fun updateGestureExclusion() {
}
- เพิ่มการตรวจสอบเพื่อข้ามการเรียกนี้ใน 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
}
- เนื่องจาก Gesture Exclusion API มีขีดจำกัดที่ 200 dp ให้ยกเว้นเฉพาะนิ้วโป้งของแถบเลื่อน รับสำเนาขอบเขตของแถบเลื่อนและเพิ่มออบเจ็กต์แต่ละรายการลงในรายการที่เปลี่ยนแปลงได้
ดูตัวอย่างโค้ดต่อไปนี้ของ 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 - Listeners to layouts
- การนำทางด้วยท่าทางสัมผัส: การปัดจากขอบด้านหนึ่งไปยังอีกด้านหนึ่ง
- การนำทางด้วยท่าทางสัมผัส: การจัดการภาพที่ทับซ้อนกัน
- การนำทางด้วยท่าทางสัมผัส: การจัดการท่าทางสัมผัสที่ขัดแย้งกัน
- ตรวจสอบความเข้ากันได้กับการไปยังส่วนต่างๆ ด้วยท่าทางสัมผัส




