1. บทนำ
สำหรับ Android เวอร์ชัน 10 ขึ้นไป โหมดใหม่รองรับท่าทางสัมผัสการนำทาง วิธีนี้ช่วยให้แอปใช้หน้าจอทั้งหมดและมอบประสบการณ์การแสดงผลที่สมจริงยิ่งขึ้นได้ เมื่อผู้ใช้เลื่อนขึ้นจากขอบด้านล่างของหน้าจอ ระบบจะนำผู้ใช้ไปยังหน้าจอหลักของ Android เมื่อผู้ใช้ปัดเข้าจากขอบด้านซ้ายหรือขวา ระบบจะนำผู้ใช้ไปยังหน้าจอก่อนหน้า
ด้วย 2 ท่าทางสัมผัสนี้ แอปของคุณจะใช้ประโยชน์จากพื้นที่ของหน้าจอที่ด้านล่างของหน้าจอได้ อย่างไรก็ตาม หากแอปใช้ท่าทางสัมผัสหรือมีการควบคุมในพื้นที่ท่าทางสัมผัสของระบบ แอปอาจทำให้เกิดความขัดแย้งกับท่าทางสัมผัสสำหรับทั้งระบบ
Codelab นี้มีจุดมุ่งหมายเพื่อสอนวิธีใช้องค์ประกอบเพื่อหลีกเลี่ยงความขัดแย้งของท่าทางสัมผัส นอกจากนี้ Codelab นี้ยังมีจุดประสงค์เพื่อสอนวิธีใช้ ท่าทางสัมผัสการยกเว้น API สำหรับการควบคุม เช่น แฮนเดิลการลาก ซึ่งจำเป็นต้องอยู่ในโซนท่าทางสัมผัส
สิ่งที่ คุณจะได้ เรียนรู้
- วิธีใช้ Listener แทรกในมุมมอง
- วิธีใช้ 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 แล้วเปลี่ยนเป็น Branch 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_STABLE
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
View.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 ของระบบเหนือแอป เราจะมาพูดคุยถึงวิธีใช้ส่วนของระบบในการย้ายตัวควบคุมออกจากแถบระบบ
- แทรกท่าทางสัมผัสของระบบ: โดยจะแสดงผลพื้นที่ท่าทางสัมผัสทั้งหมด การควบคุมการปัดในแอปในภูมิภาคเหล่านี้อาจทำให้ท่าทางสัมผัสของระบบทำงานโดยไม่ตั้งใจ
- ส่วนประกอบของท่าทางสัมผัสที่จำเป็น: ท่าทางสัมผัสเหล่านี้เป็นชุดย่อยของท่าทางสัมผัสของระบบและลบล้างไม่ได้ โดยจะบอกพื้นที่หน้าจอที่ลักษณะการทำงานของท่าทางสัมผัสของระบบจะมีความสำคัญมากกว่าท่าทางสัมผัสในแอปเสมอ
ใช้ส่วนประกอบเพื่อย้ายการควบคุมแอป
เมื่อคุณทราบข้อมูลเพิ่มเติมเกี่ยวกับ 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
อย่างไรก็ตาม การเรียกครั้งต่อๆ ไปจะเพิ่มค่าด้านล่างที่ฝังเข้าไปในระยะห่างจากขอบด้านล่างของมุมมองที่อัปเดตแล้วต่อไป
หากต้องการแก้ไข ให้ทำตามขั้นตอนต่อไปนี้
- บันทึกค่าระยะห่างจากขอบของมุมมองเริ่มต้น สร้างมูลค่าใหม่และจัดเก็บค่าระยะห่างจากขอบของมุมมองเริ่มต้น
playerView
ไว้หน้าโค้ด Listener
ดูตัวอย่างโค้ดต่อไปนี้ของ 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. API การยกเว้นท่าทางสัมผัส
ตัวควบคุมวิดีโอเพลเยอร์สำหรับความขัดแย้งด้วยท่าทางสัมผัสในพื้นที่ท่าทางสัมผัสในหน้าแรกได้รับการแก้ไขแล้ว พื้นที่ท่าทางสัมผัสการย้อนกลับอาจทำให้เกิดความขัดแย้งกับการควบคุมแอป ภาพหน้าจอต่อไปนี้แสดงให้เห็นว่าขณะนี้แถบเลื่อนของโปรแกรมเล่นอยู่ที่พื้นที่ท่าทางสัมผัสทั้งด้านขวาและซ้าย
SeekBar
จะจัดการความขัดแย้งของท่าทางสัมผัสโดยอัตโนมัติ แต่คุณอาจต้องใช้คอมโพเนนต์ UI อื่นๆ ที่ทำให้ท่าทางสัมผัสขัดแย้งกัน ในกรณีเหล่านี้ คุณสามารถใช้ Gesture Exclusion API
เพื่อเลือกไม่ใช้ท่าทางสัมผัสการย้อนกลับบางส่วน
ใช้ 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
}
- เนื่องจาก 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 — Listener ของเลย์เอาต์
- การนำทางด้วยท่าทางสัมผัส: ไปจนสุดขอบ
- การนำทางด้วยท่าทางสัมผัส: การจัดการภาพที่ทับซ้อนกัน
- การนำทางด้วยท่าทางสัมผัส: การจัดการความขัดแย้งของท่าทางสัมผัส
- ตรวจสอบความเข้ากันได้กับการนำทางด้วยท่าทางสัมผัส