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ợ như một chế độ mới. Nhờ đó, ứng dụng 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 vuốt lên từ mép dưới cùng của màn hình, người dùng sẽ được đưa đến màn hình chính của Android. Khi vuốt vào từ cạnh trái hoặc phải, người dùng sẽ được đưa về màn hình trước.

Với hai cử chỉ này, ứng dụng của bạn có thể tận dụng không gian của 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ó chế độ điều khiển trong khu vực cử chỉ của hệ thống, thì ứng dụng đó có thể xung đột với các cử chỉ trên toàn hệ thống.

Mục đích của lớp học lập trình này là 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, các lớp học lập trình này hướng dẫn bạn cách sử dụng API Loại trừ cử chỉ cho các thành phần điều khiển, chẳng hạn như ô điều khiển kéo, cần nằm trong vùng cử chỉ.

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

  • Cách dùng trình nghe phần lồng ghép trên lượt xem
  • Cách sử dụng API Loại trừ cử chỉ
  • Cách hoạt động của chế độ chìm khi dùng cử chỉ

Lớp học lập trình này hướng đến việc làm cho ứng dụng của bạn tương thích với Cử chỉ hệ thống. Những khái niệm và khối mã không liên quan sẽ được che giấu và cung cấp để 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 thao tác bằng cử chỉ.

  • Dùng phần lồng ghép để di chuyển chế độ điều khiển ra khỏi khu vực cử chỉ
  • Sử dụng API Loại trừ cử chỉ để chọn không sử dụng cử chỉ quay lại đối với các nút điều khiển xung đột
  • Sử dụng các bản dựng của bạn để khám phá các thay đổi về hành vi của chế độ chìm với 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. Phiên bản này hỗ trợ các tính năng như phát trong 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 quy trình 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 đĩ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 loa hoặc tai nghe đượ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 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ữ từ GitHub rồi chuyển sang nhánh starter (khởi động):

$  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 rồi chọn API cấp 29. Ngoài ra, bạn có thể kết nối một thiết bị thực chạy API cấp 29 trở lên.
  3. Chạy ứng dụng. Danh sách mà bạn thấy nhóm các bài hát vào 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 sẽ bắt đầu phát bài hát.

Bật 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ó API cấp 29, thì có thể tính năng Thao tác bằng cử chỉ chưa được bật theo mặc định. Để bật Thao tác bằng cử chỉ, hãy chọn Cài đặt hệ thống > Hệ thống > Di chuyển hệ thống > Thao tác bằng cử chỉ.

Chạy ứng dụng bằng tính năng Thao tác bằng cử chỉ

Nếu bạn chạy ứng dụng đã bật Điều hướng bằng cử chỉ và bắt đầu phát lại 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 ở rất gần khu vực màn hình chính và khu vực cử chỉ quay lại.

4. tràn viền

Chiến dịch hiển thị 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 màn hình tràn viền, bất kể cử chỉ hoặc nút có được bật để điều hướng 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 làm cho nền của thanh điều hướng 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 trên 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. Navigation bar (Thanh điều hướng): Mở res/values-29/styles.xml rồi đặt navigationBarColor thành color/transparent.
  2. Thanh trạng thái: Tương tự, đặt statusBarColor thành color/transparent.

Hãy xem 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ờ chế độ hiển thị giao diện người dùng hệ thống

Bạn cũng phải đặt cờ chế độ hiển thị giao diện người dùng hệ thống để yêu cầu hệ thống bố trí ứng dụng bên dưới các thanh hệ thống. API systemUiVisibility trên lớp View cho phép đặ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(). Nhận một thực thể của fragmentContainer.
  2. Đặt các giá trị sau thành content.systemUiVisibility:

Hãy xem 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 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 rồi chuyển đến màn hình trình phát, hãy chọn một bài hát để 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ó sử dụng các nút này:

  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 chế độ điều khiển thậm chí còn khó sử dụng hơn trên thanh điều hướng có 3 nút: Lưu ý SeekBar bị ẩn phía sau thanh điều hướng và chức năng Phát/Tạm dừng gần như bị thanh điều hướng che phủ.
  3. Hãy tìm hiểu 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 quay lại thao tác Điều hướng bằng cử chỉ:

741ef664e9be5e7f.gif

Ứng dụng hiện đang hiển thị tràn viền, nhưng có một số vấn đề về khả năng hữu dụng, các chế độ kiểm soát ứng dụng gây xung đột và chồng chéo nhau và những vấn đề này phải được giải quyết.

5. Phần 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 như khu vực nào trên màn hình mà Cử chỉ hệ thống được ưu tiên hơn so với cử chỉ trong ứng dụng. Các 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 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à các API phần lồng ghép được dùng phổ biến nhất:

  • Phần lồng ghép cửa sổ hệ thống: Các phần lồng ghép này cho bạn biết vị trí hiển thị giao diện người dùng hệ thống 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 các phần lồng ghép hệ thống để di chuyển chế độ điều khiển ra khỏi thanh hệ thống.
  • Phần lồng ghép cử chỉ hệ thống: Trả về tất cả các khu vực 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 ghép cử chỉ bắt buộc: Đây là một tập hợp con của các phần lồng ghép cử chỉ hệ thống và không thể ghi đè. Chúng cho bạn biết các vùng màn hình nơi hoạt động của Cử chỉ hệ thống sẽ luôn được ưu tiên hơn so với các 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ể khắc phục các chế độ điều khiển ứng dụng như mô tả ở các bước sau:

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

Hãy xem 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 có vẻ như không có gì thay đổi trong các nút điều khiển trình phát. Nếu thêm điểm ngắt và chạy ứng dụng ở chế độ gỡ lỗi, bạn sẽ thấy trình nghe sẽ không được gọi.
  2. Để khắc phục vấn đề này, hãy chuyển sang FragmentContainerView để tự động xử lý vấn đề này. Mở activity_main.xml và thay đổi FrameLayout thành FragmentContainerView.

Hãy xem 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 được dịch chuyển ra khỏi khu vực cử chỉ dưới cùng.

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

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

Nếu bạn chuyển sang ứ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 chú ý 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 này bắt đầu. Ngay cả khi không có lệnh gọi này, WindowInsets vẫn có thể được gửi đ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 ngay lần đầu tiên khi bạn thêm giá trị giá trị dưới cùng của phần lồng ghép 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ị dưới cùng của phần lồng ghép vào khoảng đệm dưới cùng của thành phần 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 của thành phần hiển thị ban đầu. Tạo một val mới và lưu trữ giá trị khoảng đệm khung hiển thị ban đầu của playerView, ngay trước mã trình nghe.

Hãy xem mã mẫu sau đây của NowPlayingFragment.kt:

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

Hãy xem 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 trả 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 khu vực cử chỉ.

Thiết kế lại các chế độ điều khiển ứng dụng

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

Việc sử dụng phần lồng ghép cho phép bạn khắc phục xung đột cử chỉ. Tuy nhiên, đôi khi với những thay đổi nhỏ về thiết kế, bạn có thể hoàn toàn tránh được 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 biểu tượng 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 hai thanh tua thành parent.
  3. Để ràng buộc các mục khác trong playerView với đáy của SeekBar, hãy thay đổi layout_constraintTop_toTopOf từ cấp độ gốc thành @+id/seekBar trên media_button, titleposition.

Hãy xem 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 và thanh tua.

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

6. API loại trừ cử chỉ

Các nút điều khiển trình phát cho trường hợp xung đột cử chỉ trong khu vực cử chỉ trên màn hình chính đã được khắc phục. Khu vực cử chỉ quay lại cũng có thể tạo ra xung đột với các nút điều khiển ứ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 nằm ở cả khu vực cử chỉ quay lại bên phải và bên trái:

e6d98e94dcf83dde.png

SeekBar tự động xử lý xung đột cử chỉ. Tuy nhiên, bạn có thể cần sử dụng các thành phần giao diện người dùng khác 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 API Loại trừ cử chỉ

Để tạo một vùng loại trừ cử chỉ, hãy gọi setSystemGestureExclusionRects() trên khung hiển thị của bạn kèm theo danh sách đố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ừ. Lệnh gọi này phải được thực hiện trong phương thức onLayout() hoặc onDraw() của khung hiển thị. Để thực hiện việc này, hãy thực hiện các bước sau:

  1. Tạo một gói mới 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.

Hãy xem 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().

Hãy xem mã mẫu sau đây của MySeekBar.kt:

private fun updateGestureExclusion() {

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

Hãy xem 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ì API Loại trừ cử chỉ có giới hạn là 200 dp, nên bạn chỉ cần loại trừ nút thumb của thanh tua. Lấy bản sao các giới hạn của thanh tua rồi thêm từng đối tượng vào một danh sách có thể thay đổi.

Hãy xem 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 danh sách gestureExclusionRects mà bạn tạo.

Hãy xem 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 một lệnh gọi đến updateGestureExclusion.

Hãy xem 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 tệp 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.

Hãy xem 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 tham chiếu SeekBar trong NowPlayingFragment.kt, mở NowPlayingFragment.kt và thay đổi loại positionSeekBar thành MySeekBar. Để khớp với loại biến, hãy thay đổi thông số tổng quát SeekBar cho lệnh gọi findViewById thành MySeekBar.

Hãy xem 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 tình trạng xung đột cử chỉ, bạn có thể thử nghiệm và sửa đổi giới hạn ngón cái trong MySeekBar. Hãy cẩn thận để không tạo một vùng loại trừ cử chỉ lớn hơn mức cần thiết, vì việc này sẽ hạn chế các lệnh gọi loại trừ cử chỉ có thể có khác và dẫn đến 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 bằng Cử chỉ hệ thống!

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

Giờ đây, bạn đã biết các bước chính cần thiết để giúp ứng dụng hoạt động với Cử chỉ hệ thống!

Tài liệu bổ sung

Tài liệu tham khảo