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

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

ทำตามขั้นตอนต่อไปนี้ให้เสร็จ

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

ใช้ส่วนประกอบเพื่อย้ายการควบคุมแอป

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

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

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

ดูตัวอย่างโค้ดต่อไปนี้ของ 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 ของ SeekBar เป็น 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. API การยกเว้นท่าทางสัมผัส

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

e6d98e94dcf83dde.png

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

ใช้ 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. เนื่องจาก 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. ขอแสดงความยินดี

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

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

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

สื่อเพิ่มเติม

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