การนำทางด้วยท่าทางสัมผัสและประสบการณ์แบบไร้ขอบ

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 ก็ได้

ทำตามขั้นตอนต่อไปนี้ให้ครบถ้วน

  1. เปิดและสร้างแอปใน Android Studio
  2. สร้างอุปกรณ์เสมือนใหม่และเลือก 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>

แฟล็กการแสดง UI ของระบบ

นอกจากนี้ คุณยังต้องตั้งค่าสถานะระดับการเข้าถึง UI ของระบบเพื่อบอกให้ระบบจัดวางแอปไว้ใต้แถบระบบ API ของ systemUiVisibility ในคลาส View ช่วยให้ตั้งค่า Flag ได้หลากหลาย ทำตามขั้นตอนต่อไปนี้

  1. เปิดMainActivity.ktชั้นเรียนและหาวิธี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. ตรวจสอบว่าแถบนำทางแบบ 3 ปุ่มทำให้ควบคุมได้ยากยิ่งขึ้น: สังเกตว่า SeekBar ซ่อนอยู่หลังแถบนำทาง และเล่น/หยุดชั่วคราวส่วนใหญ่ถูกแถบนำทางบดบัง
  3. ลองสำรวจและทดลองดู หลังจากดำเนินการเสร็จแล้ว ให้ไปที่การตั้งค่าระบบและเปลี่ยนกลับไปใช้การนำทางด้วยท่าทางสัมผัสโดยทำดังนี้

741ef664e9be5e7f.gif

ตอนนี้แอปวาดภาพแบบขอบถึงขอบแล้ว แต่ยังมีปัญหาด้านความสามารถในการใช้งาน การควบคุมแอปที่ขัดแย้งและทับซ้อนกัน ซึ่งต้องได้รับการแก้ไข

5. ข้างใน

WindowInsets จะบอกแอปว่า UI ของระบบปรากฏที่ด้านบนของเนื้อหาที่ใด รวมถึงภูมิภาคใดของหน้าจอที่ท่าทางสัมผัสของระบบมีความสำคัญเหนือกว่าท่าทางสัมผัสในแอป โดยมีคลาส WindowInsets และคลาส WindowInsetsCompat ใน Jetpack เราขอแนะนำเป็นอย่างยิ่งให้ใช้ WindowInsetsCompat เพื่อให้มีลักษณะการทำงานที่สอดคล้องกันใน API ทุกระดับ

การแทรกระบบและการแทรกระบบที่บังคับ

API การแทรกต่อไปนี้เป็นประเภทการแทรกที่ใช้กันมากที่สุด

  • ระยะขอบหน้าต่างของระบบ: ระยะขอบเหล่านี้จะบอกตำแหน่งที่ UI ของระบบแสดงเหนือแอปของคุณ เราจะพูดถึงวิธีใช้ระยะขอบของระบบเพื่อย้ายการควบคุมออกจากแถบของระบบ
  • การแทรกท่าทางสัมผัสของระบบ: แสดงผลพื้นที่ท่าทางสัมผัสทั้งหมด การควบคุมด้วยการปัดในแอปในภูมิภาคเหล่านี้อาจทําให้ท่าทางสัมผัสของระบบทํางานโดยไม่ตั้งใจ
  • ระยะขอบท่าทางสัมผัสที่บังคับ: เป็นส่วนย่อยของระยะขอบท่าทางสัมผัสของระบบและจะลบล้างไม่ได้ ซึ่งจะบอกให้คุณทราบบริเวณของหน้าจอที่ลักษณะการทำงานของท่าทางสัมผัสของระบบจะมีความสำคัญเหนือกว่าท่าทางสัมผัสในแอปเสมอ

ใช้ Inset เพื่อย้ายตัวควบคุมแอป

ตอนนี้คุณทราบข้อมูลเพิ่มเติมเกี่ยวกับ 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. เรียกใช้แอปแล้วเลือกเพลง โปรดสังเกตว่าตัวควบคุมวิดีโอเพลเยอร์จะไม่มีอะไรเปลี่ยนแปลง หากเพิ่มเบรกพอยต์และเรียกใช้แอปในโหมดแก้ไขข้อบกพร่อง คุณจะเห็นว่าระบบไม่ได้เรียกใช้ Listener
  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. บันทึกค่าการเพิ่มพื้นที่โฆษณาของมุมมองเริ่มต้น สร้าง val ใหม่และจัดเก็บค่าการเว้นวรรคมุมมองเริ่มต้นของ playerView ไว้ก่อนโค้ด Listener

ดูตัวอย่างโค้ดต่อไปนี้ของ NowPlayingFragment.kt

   val initialPadding = playerView.paddingBottom
  1. ใช้ค่าเริ่มต้นนี้เพื่ออัปเดตระยะห่างจากด้านล่างของ View ซึ่งจะช่วยให้คุณหลีกเลี่ยงการใช้ค่าระยะห่างจากด้านล่างปัจจุบันของแอปได้

ดูตัวอย่างโค้ดต่อไปนี้ของ NowPlayingFragment.kt

   playerView.setOnApplyWindowInsetsListener { view, insets ->
            view.updatePadding(bottom = insets.systemWindowInsetBottom + initialPadding)
            insets
        }
  1. เรียกใช้แอปอีกครั้ง ไปยังบริเวณต่างๆ ระหว่างแอปและไปที่หน้าจอหลัก เมื่อกลับไปที่แอป ตัวควบคุมวิดีโอเพลเยอร์จะอยู่เหนือพื้นที่ท่าทางสัมผัส

ออกแบบการควบคุมแอปใหม่

แถบเลื่อนของเพลเยอร์อยู่ใกล้กับพื้นที่ท่าทางสัมผัสที่ด้านล่างมากเกินไป ซึ่งหมายความว่าผู้ใช้อาจเรียกใช้ท่าทางสัมผัสหน้าแรกโดยไม่ตั้งใจเมื่อปัดในแนวนอนจนเสร็จ หากเพิ่มระยะเว้นมากยิ่งขึ้น ปัญหานี้อาจได้รับการแก้ไข แต่ก็อาจทำให้ผู้เล่นเลื่อนขึ้นสูงกว่าที่ต้องการด้วย

การใช้ระยะขอบช่วยให้คุณแก้ไขความขัดแย้งของท่าทางสัมผัสได้ แต่ในบางครั้งการเปลี่ยนแปลงการออกแบบเล็กๆ น้อยๆ ก็ช่วยหลีกเลี่ยงความขัดแย้งของท่าทางสัมผัสได้ทั้งหมด หากต้องการออกแบบตัวควบคุมวิดีโอเพลเยอร์ใหม่เพื่อหลีกเลี่ยงการขัดแย้งของท่าทางสัมผัส ให้ทำตามขั้นตอนต่อไปนี้

  1. เปิด fragment_nowplaying.xml เปลี่ยนไปเป็นมุมมองการออกแบบ แล้วเลือก SeekBar ที่ด้านล่างสุด

74918dec3926293f.png

  1. เปลี่ยนเป็นมุมมองโค้ด
  2. หากต้องการย้าย SeekBar ไปที่ด้านบนของ playerLayout ให้เปลี่ยน layout_constraintTop_toBottomOf ของแถบเลื่อนเป็น parent
  3. หากต้องการจำกัดรายการอื่นๆ ใน 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>
  1. เรียกใช้แอปและโต้ตอบกับเพลเยอร์และแถบเลื่อน

การเปลี่ยนแปลงการออกแบบเพียงเล็กน้อยเหล่านี้ช่วยปรับปรุงแอปได้อย่างมาก

6. Gesture Exclusion API

แก้ไขตัวควบคุมวิดีโอเพลเยอร์สำหรับการขัดแย้งของท่าทางสัมผัสในพื้นที่ท่าทางสัมผัสหน้าแรกแล้ว นอกจากนี้ พื้นที่ท่าทางสัมผัสย้อนกลับยังอาจขัดแย้งกับการควบคุมแอปได้ด้วย ภาพหน้าจอต่อไปนี้แสดงให้เห็นว่าแถบเลื่อนของวิดีโอเพลเยอร์อยู่ในพื้นที่ท่าทางสัมผัสย้อนกลับทั้งด้านขวาและด้านซ้ายในปัจจุบัน

e6d98e94dcf83dde.png

SeekBar จะจัดการความขัดแย้งของท่าทางสัมผัสโดยอัตโนมัติ แต่คุณอาจต้องใช้คอมโพเนนต์ UI อื่นๆ ที่ทำให้เกิดการขัดแย้งของท่าทางสัมผัส ในกรณีเหล่านี้ คุณสามารถใช้ 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 มีขีดจำกัดที่ 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()
    }
}
  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. เรียกใช้เมธอด 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. ขอแสดงความยินดี

ยินดีด้วย คุณได้เรียนรู้วิธีหลีกเลี่ยงและแก้ไขการทับซ้อนกันด้วยท่าทางสัมผัสของระบบแล้ว

คุณทำให้แอปใช้แบบเต็มหน้าจอเมื่อขยายจากขอบจรดขอบและใช้ระยะขอบเพื่อย้ายตัวควบคุมแอปออกจากโซนท่าทางสัมผัส นอกจากนี้ คุณยังได้เรียนรู้วิธีปิดใช้ท่าทางสัมผัสเพื่อย้อนกลับของระบบในการควบคุมแอปด้วย

ตอนนี้คุณทราบขั้นตอนสำคัญที่จำเป็นในการทำให้แอปทำงานร่วมกับท่าทางสัมผัสของระบบแล้ว

สื่อการสอนเพิ่มเติม

เอกสารอ้างอิง