Thao tác bằng cử chỉ và trải nghiệm các ứng dụng đặt cạnh nhau

1. Giới thiệu

Đối với Android phiên bản 10 trở lên, cử chỉ điều hướng được hỗ trợ dưới dạng một chế độ mới. Nhờ đó, ứng dụng của bạn có thể sử dụng toàn bộ màn hình và mang lại trải nghiệm hiển thị sống động hơn. Khi người dùng vuốt lên từ cạnh dưới cùng của màn hình, họ sẽ được đưa đến màn hình chính của Android. Khi người dùng vuốt từ mép trái hoặc mép phải vào trong, thao tác này sẽ đưa người dùng đến màn hình trước đó.

Với 2 cử chỉ này, ứng dụng của bạn có thể tận dụng không gian màn hình ở cuối màn hình. Tuy nhiên, nếu ứng dụng của bạn sử dụng cử chỉ hoặc có các chế độ kiểm soát trong vùng cử chỉ hệ thống, thì điều này có thể gây xung đột với các cử chỉ trên toàn hệ thống.

Lớp học lập trình này nhằm mục đích hướng dẫn bạn cách sử dụng phần lồng ghép để tránh xung đột cử chỉ. Ngoài ra, lớp học lập trình này còn hướng dẫn bạn cách sử dụng Gesture Exclusion API cho các chế độ kiểm soát (chẳng hạn như tay cầm kéo) cần nằm trong vùng cử chỉ.

Kiến thức bạn sẽ học được

  • Cách sử dụng trình nghe phần lồng ghép trên khung hiển thị
  • Cách sử dụng Gesture Exclusion API
  • Cách chế độ sống động hoạt động khi cử chỉ đang hoạt động

Lớp học lập trình này nhằm mục đích giúp ứng dụng của bạn tương thích với Cử chỉ hệ thống. Các khái niệm và khối mã không liên quan được tinh chỉnh và cung cấp cho bạn để sao chép và dán.

Sản phẩm bạn sẽ tạo ra

Universal Android Music Player (UAMP) là một ứng dụng trình phát nhạc mẫu dành cho Android được viết bằng Kotlin. Bạn sẽ thiết lập UAMP cho chế độ thao tác bằng cử chỉ.

  • Sử dụng phần lồng ghép để di chuyển các nút điều khiển ra khỏi vùng cử chỉ
  • Sử dụng Gesture Exclusion API để chọn không sử dụng cử chỉ quay lại cho các chế độ kiểm soát xung đột
  • Sử dụng các bản dựng để khám phá những thay đổi về hành vi ở chế độ sống động bằng chế độ Thao tác bằng cử chỉ

Bạn cần có

  • Một thiết bị hoặc trình mô phỏng chạy Android 10 trở lên
  • Android Studio

2. Tổng quan về ứng dụng

Universal Android Music Player (UAMP) là một ứng dụng trình phát nhạc mẫu dành cho Android được viết bằng Kotlin. Thư viện này hỗ trợ các tính năng như phát ở chế độ nền, xử lý quyền phát âm thanh, tích hợp Trợ lý và nhiều nền tảng như Wear, TV và Auto.

Hình 1: Một luồng trong UAMP

UAMP tải danh mục nhạc từ một máy chủ từ xa và cho phép người dùng duyệt xem các đĩa nhạc và bài hát. Người dùng nhấn vào một bài hát và bài hát đó sẽ phát qua tai nghe hoặc loa được kết nối. Ứng dụng này không được thiết kế để hoạt động với Cử chỉ hệ thống. Do đó, khi chạy UAMP trên một thiết bị chạy Android 10 trở lên, ban đầu bạn sẽ gặp phải một số vấn đề.

3. Bắt đầu thiết lập

Để tải ứng dụng mẫu, hãy sao chép kho lưu trữ trên GitHub rồi chuyển sang nhánh starter:

$  git clone https://github.com/googlecodelabs/android-gestural-navigation/

Ngoài ra, bạn có thể tải kho lưu trữ xuống dưới dạng tệp zip rồi giải nén và mở trong Android Studio.

Hãy hoàn tất các bước sau:

  1. Mở và tạo ứng dụng trong Android Studio.
  2. Tạo một thiết bị ảo mới và chọn cấp độ API 29. Ngoài ra, bạn có thể kết nối một thiết bị thực chạy cấp độ API 29 trở lên.
  3. Chạy ứng dụng. Danh sách bạn thấy sẽ nhóm các bài hát thành các lựa chọn Đề xuấtĐĩa nhạc.
  4. Nhấp vào Đề xuất rồi chọn một bài hát trong danh sách bài hát.
  5. Ứng dụng bắt đầu phát bài hát.

Bật chế độ thao tác bằng cử chỉ

Nếu bạn chạy một phiên bản trình mô phỏng mới có cấp độ API 29, thì chế độ điều hướng bằng cử chỉ có thể không được bật theo mặc định. Để bật chế độ Thao tác bằng cử chỉ, hãy chọn Cài đặt hệ thống > Hệ thống > Chế độ thao tác bằng cử chỉ.

Chạy ứng dụng bằng chế độ Thao tác bằng cử chỉ

Nếu chạy ứng dụng khi bật chế độ Thao tác bằng cử chỉ và bắt đầu phát một bài hát, bạn có thể nhận thấy các nút điều khiển trình phát nằm rất gần các vùng cử chỉ quay lại và chuyển đến màn hình chính.

4. Chuyển sang chế độ tràn viền

Chế độ tràn viền là gì?

Các ứng dụng chạy trên Android 10 trở lên có thể mang đến trải nghiệm toàn màn hình tràn viền, bất kể bạn có bật cử chỉ hay nút để thao tác hay không. Để mang đến trải nghiệm tràn viền, ứng dụng phải vẽ phía sau thanh điều hướng và thanh trạng thái trong suốt.

Vẽ phía sau thanh điều hướng

Để ứng dụng của bạn hiển thị nội dung bên dưới thanh điều hướng, trước tiên, bạn phải thiết lập nền của thanh điều hướng thành trong suốt. Sau đó, bạn phải làm cho thanh trạng thái trong suốt. Điều này cho phép ứng dụng của bạn hiển thị ứng dụng theo toàn bộ chiều cao của màn hình.

Để thay đổi màu của thanh điều hướng và thanh trạng thái, hãy thực hiện các bước sau:

  1. Thanh điều hướng: Mở res/values-29/styles.xml và đặt navigationBarColor thành color/transparent.
  2. Thanh trạng thái: Tương tự, hãy đặt statusBarColor thành color/transparent.

Xem lại mã mẫu sau đây của 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>

Cờ hiển thị giao diện người dùng hệ thống

Bạn cũng phải đặt cờ hiển thị giao diện người dùng hệ thống để cho hệ thống biết cách bố trí ứng dụng bên dưới các thanh hệ thống. Các API systemUiVisibility trên lớp View cho phép bạn đặt nhiều cờ. Thực hiện các bước sau đây:

  1. Mở lớp MainActivity.kt rồi tìm phương thức onCreate(). Tạo một thực thể của fragmentContainer.
  2. Đặt các mục sau thành content.systemUiVisibility:

Xem lại mã mẫu sau đây của 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

Khi đặt các cờ này cùng nhau, bạn cho hệ thống biết rằng bạn muốn ứng dụng của mình hiển thị ở chế độ toàn màn hình như thể không có thanh điều hướng và thanh trạng thái. Thực hiện các bước sau đây:

  1. Chạy ứng dụng và chọn một bài hát để phát nhằm chuyển đến màn hình trình phát.
  2. Xác minh rằng các nút điều khiển trình phát được vẽ bên dưới thanh điều hướng, khiến người dùng khó truy cập:

  1. Chuyển đến phần Cài đặt hệ thống, chuyển về chế độ thao tác bằng 3 nút rồi quay lại ứng dụng.
  2. Xác minh rằng các nút điều khiển sẽ càng khó sử dụng hơn khi có thanh điều hướng gồm 3 nút: Lưu ý rằng nút SeekBar bị ẩn sau thanh điều hướng và nút Phát/Tạm dừng hầu hết bị thanh điều hướng che khuất.
  3. Khám phá và thử nghiệm một chút. Sau khi hoàn tất, hãy chuyển đến phần Cài đặt hệ thống rồi chuyển về chế độ Điều hướng bằng cử chỉ:

741ef664e9be5e7f.gif

Ứng dụng hiện đang vẽ tràn viền, nhưng có các vấn đề về khả năng sử dụng, các chế độ kiểm soát ứng dụng xung đột và chồng chéo, bạn phải giải quyết những vấn đề này.

5. Lồng ghép

WindowInsets cho ứng dụng biết vị trí giao diện người dùng hệ thống xuất hiện trên nội dung của bạn, cùng với những vùng trên màn hình mà Cử chỉ hệ thống được ưu tiên hơn cử chỉ trong ứng dụng. Phần lồng ghép được biểu thị bằng lớp WindowInsets và lớp WindowInsetsCompat trong Jetpack. Bạn nên sử dụng WindowInsetsCompat để có hành vi nhất quán trên tất cả các cấp độ API.

Phần lồng ghép hệ thống và phần lồng ghép hệ thống bắt buộc

Sau đây là những API phần lồng ghép thường dùng nhất:

  • Phần lồng ghép cửa sổ hệ thống: Các phần này cho biết vị trí giao diện người dùng hệ thống hiển thị trên ứng dụng của bạn. Chúng ta sẽ thảo luận về cách bạn có thể sử dụng phần lồng ghép hệ thống để di chuyển các chế độ kiểm soát ra khỏi thanh hệ thống.
  • Phần lồng ghép cử chỉ hệ thống: Chúng trả về tất cả các vùng cử chỉ. Mọi thao tác vuốt trong ứng dụng ở những khu vực này đều có thể vô tình kích hoạt Cử chỉ hệ thống.
  • Phần lồng cử chỉ bắt buộc: Đây là một tập hợp con của phần lồng cử chỉ hệ thống và không thể ghi đè. Chúng cho biết những vùng trên màn hình mà hành vi của Cử chỉ hệ thống sẽ luôn được ưu tiên hơn cử chỉ trong ứng dụng.

Sử dụng phần lồng ghép để di chuyển các chế độ điều khiển ứng dụng

Giờ đây, khi đã biết thêm về các API phần lồng ghép, bạn có thể sửa các chế độ kiểm soát ứng dụng như mô tả trong các bước sau:

  1. Tạo một thực thể của playerLayout từ thực thể đối tượng view.
  2. Thêm OnApplyWindowInsetsListener vào playerView.
  3. Di chuyển khung hiển thị ra khỏi vùng cử chỉ: Tìm giá trị phần lồng ghép hệ thống cho phần dưới cùng và tăng khoảng đệm của khung hiển thị theo giá trị đó. Để cập nhật khoảng đệm của khung hiển thị cho phù hợp, hãy thêm [giá trị liên kết với khoảng đệm dưới cùng của ứng dụng] vào [giá trị liên kết với giá trị phần lồng ghép dưới cùng của hệ thống].

Xem lại mã mẫu sau đây của NowPlayingFragment.kt:

playerView = view.findViewById(R.id.playerLayout)
playerView.setOnApplyWindowInsetsListener { view, insets ->
   view.updatePadding(
      bottom = insets.systemWindowInsetBottom + view.paddingBottom
   )
   insets
}
  1. Chạy ứng dụng rồi chọn một bài hát. Lưu ý rằng không có gì thay đổi trong các nút điều khiển trình phát. Nếu thêm một điểm ngắt và chạy ứng dụng ở chế độ gỡ lỗi, bạn sẽ thấy trình nghe không được gọi.
  2. Để khắc phục vấn đề này, hãy chuyển sang FragmentContainerView. Thư viện này sẽ tự động xử lý vấn đề này. Mở activity_main.xml và thay đổi FrameLayout thành FragmentContainerView.

Xem lại mã mẫu sau đây của 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. Chạy lại ứng dụng và chuyển đến màn hình trình phát. Các nút điều khiển trình phát ở dưới cùng sẽ được chuyển ra khỏi khu vực cử chỉ ở dưới cùng.

Giờ đây, các chế độ điều khiển ứng dụng hoạt động với chế độ Thao tác bằng cử chỉ, nhưng các chế độ điều khiển di chuyển nhiều hơn dự kiến. Bạn phải giải quyết vấn đề này.

Giữ nguyên khoảng đệm và lề hiện tại

Nếu bạn chuyển sang các ứng dụng khác hoặc chuyển đến màn hình chính rồi quay lại ứng dụng mà không đóng ứng dụng, hãy lưu ý rằng các nút điều khiển trình phát sẽ di chuyển lên mỗi lần.

Điều này là do ứng dụng kích hoạt requestApplyInsets() mỗi khi hoạt động bắt đầu. Ngay cả khi không có lệnh gọi này, WindowInsets vẫn có thể được gửi nhiều lần bất cứ lúc nào trong vòng đời của một khung hiển thị.

InsetListener hiện tại trên playerView hoạt động hoàn hảo trong lần đầu tiên khi bạn thêm số tiền giá trị phần lồng ghép dưới cùng vào giá trị khoảng đệm dưới cùng của ứng dụng được khai báo trong activity_main.xml. Tuy nhiên, các lệnh gọi tiếp theo sẽ tiếp tục thêm giá trị phần lồng ghép dưới cùng vào khoảng đệm dưới cùng của khung hiển thị đã cập nhật.

Để khắc phục vấn đề này, hãy thực hiện các bước sau:

  1. Ghi lại giá trị khoảng đệm ban đầu của khung hiển thị. Tạo một val mới và lưu trữ giá trị khoảng đệm ban đầu của khung hiển thị playerView, ngay trước mã trình nghe.

Xem lại mã mẫu sau đây của NowPlayingFragment.kt:

   val initialPadding = playerView.paddingBottom
  1. Sử dụng giá trị ban đầu này để cập nhật khoảng đệm dưới cùng của khung hiển thị, giúp bạn tránh sử dụng giá trị khoảng đệm dưới cùng hiện tại của ứng dụng.

Xem lại mã mẫu sau đây của NowPlayingFragment.kt:

   playerView.setOnApplyWindowInsetsListener { view, insets ->
            view.updatePadding(bottom = insets.systemWindowInsetBottom + initialPadding)
            insets
        }
  1. Chạy lại ứng dụng. Di chuyển giữa các ứng dụng và chuyển đến màn hình chính. Khi bạn quay lại ứng dụng, các nút điều khiển trình phát sẽ nằm ngay phía trên vùng cử chỉ.

Thiết kế lại các chế độ kiểm soát ứng dụng

Thanh tua của trình phát quá gần khu vực cử chỉ ở dưới cùng, tức là người dùng có thể vô tình kích hoạt cử chỉ về màn hình chính khi hoàn tất thao tác vuốt ngang. Nếu bạn tăng khoảng đệm hơn nữa, vấn đề này có thể được giải quyết, nhưng người chơi cũng có thể di chuyển lên cao hơn mức mong muốn.

Việc sử dụng phần lồng ghép giúp bạn khắc phục xung đột cử chỉ, nhưng đôi khi, chỉ cần thay đổi nhỏ về thiết kế, bạn có thể tránh hoàn toàn xung đột cử chỉ. Để thiết kế lại các nút điều khiển trình phát nhằm tránh xung đột cử chỉ, hãy thực hiện các bước sau:

  1. Mở fragment_nowplaying.xml. Chuyển sang chế độ xem Thiết kế rồi chọn SeekBar ở dưới cùng:

74918dec3926293f.png

  1. Chuyển sang Chế độ xem mã.
  2. Để di chuyển SeekBar lên đầu playerLayout, hãy thay đổi layout_constraintTop_toBottomOf của SeekBar thành parent.
  3. Để ràng buộc các mục khác trong playerView với phần dưới cùng của SeekBar, hãy thay đổi layout_constraintTop_toTopOf từ parent thành @+id/seekBar trên media_button, titleposition.

Xem lại mã mẫu sau đây của 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. Chạy ứng dụng và tương tác với trình phát cũng như thanh tìm kiếm.

Những thay đổi nhỏ về thiết kế này giúp cải thiện đáng kể ứng dụng.

6. Gesture Exclusion API

Các nút điều khiển trình phát cho các cử chỉ xung đột trong vùng cử chỉ trên màn hình chính đã được cố định. Vùng thao tác bằng cử chỉ quay lại cũng có thể xung đột với các chế độ kiểm soát của ứng dụng. Ảnh chụp màn hình sau đây cho thấy thanh tua của trình phát hiện đang nằm ở cả vùng thao tác bằng cử chỉ quay lại bên phải và bên trái:

e6d98e94dcf83dde.png

SeekBar tự động xử lý các xung đột về cử chỉ. Tuy nhiên, bạn có thể cần sử dụng các thành phần khác trên giao diện người dùng để kích hoạt xung đột cử chỉ. Trong những trường hợp này, bạn có thể dùng Gesture Exclusion API để chọn không sử dụng một phần cử chỉ quay lại.

Sử dụng Gesture Exclusion API

Để tạo một vùng loại trừ cử chỉ, hãy gọi setSystemGestureExclusionRects() trên khung hiển thị bằng danh sách các đối tượng rect. Các đối tượng rect này liên kết với toạ độ của các vùng hình chữ nhật bị loại trừ. Bạn phải thực hiện lệnh gọi này trong phương thức onLayout() hoặc onDraw() của khung hiển thị. Để làm như vậy, hãy thực hiện các bước sau:

  1. Tạo một gói mới có tên là view.
  2. Để gọi API này, hãy tạo một lớp mới có tên là MySeekBar và mở rộng AppCompatSeekBar.

Xem lại mã mẫu sau đây của 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. Tạo một phương thức mới có tên là updateGestureExclusion().

Xem lại mã mẫu sau đây của MySeekBar.kt:

private fun updateGestureExclusion() {

}
  1. Thêm một bước kiểm tra để bỏ qua lệnh gọi này ở cấp độ API 28 trở xuống.

Xem lại mã mẫu sau đây của MySeekBar.kt:

private fun updateGestureExclusion() {
        // Skip this call if we're not running on Android 10+
        if (Build.VERSION.SDK_INT < 29) return
}
  1. Vì Gesture Exclusion API có giới hạn là 200 dp, nên bạn chỉ cần loại trừ ngón tay cái của thanh tìm kiếm. Lấy bản sao của ranh giới thanh tìm kiếm và thêm từng đối tượng vào một danh sách có thể thay đổi.

Xem lại mã mẫu sau đây của 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. Gọi systemGestureExclusionRects() bằng các danh sách gestureExclusionRects mà bạn tạo.

Xem lại mã mẫu sau đây của 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. Gọi phương thức updateGestureExclusion() từ onDraw() hoặc onLayout(). Ghi đè onDraw() và thêm lệnh gọi đến updateGestureExclusion.

Xem lại mã mẫu sau đây của MySeekBar.kt:

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    updateGestureExclusion()
}
  1. Bạn phải cập nhật các tham chiếu SeekBar. Để bắt đầu, hãy mở fragment_nowplaying.xml.
  2. Thay đổi SeekBar thành com.example.android.uamp.view.MySeekBar.

Xem lại mã mẫu sau đây của 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. Để cập nhật các tham chiếu SeekBar trong NowPlayingFragment.kt, hãy mở NowPlayingFragment.kt và thay đổi loại positionSeekBar thành MySeekBar. Để khớp với kiểu biến, hãy thay đổi kiểu chung SeekBar cho lệnh gọi findViewById thành MySeekBar.

Xem lại mã mẫu sau đây của NowPlayingFragment.kt:

val positionSeekBar: MySeekBar = view.findViewById<MySeekBar>(
     R.id.seekBar
).apply { progress = 0 }
  1. Chạy ứng dụng và tương tác với SeekBar. Nếu vẫn gặp phải xung đột cử chỉ, bạn có thể thử nghiệm và sửa đổi ranh giới ngón tay cái trong MySeekBar. Hãy cẩn thận để không tạo vùng loại trừ cử chỉ lớn hơn mức cần thiết, vì điều này sẽ hạn chế các lệnh gọi loại trừ cử chỉ tiềm năng khác và tạo ra hành vi không nhất quán cho người dùng.

7. Xin chúc mừng

Xin chúc mừng! Bạn đã tìm hiểu cách tránh và giải quyết xung đột với Cử chỉ trên hệ thống!

Bạn đã thiết lập để ứng dụng sử dụng toàn màn hình khi bạn mở rộng chế độ hiển thị tràn viền và dùng phần lồng ghép để di chuyển các chế độ kiểm soát ứng dụng ra khỏi vùng cử chỉ. Bạn cũng đã tìm hiểu cách tắt cử chỉ quay lại của hệ thống trên các chế độ kiểm soát ứng dụng.

Giờ đây, bạn đã biết các bước quan trọng cần thiết để ứng dụng của bạn hoạt động với Cử chỉ hệ thống!

Tài liệu bổ sung

Tài liệu tham khảo