Tạo hiệu ứng Chuyển đổi đẹp mắt bằng Material Motion dành cho Android

1. Giới thiệu

Material Design là hệ thống để tạo các sản phẩm kỹ thuật số đẹp mắt và ấn tượng. Bằng cách hợp nhất phong cách, cách xây dựng thương hiệu, sự tương tác và chuyển động theo một bộ nguyên tắc và thành phần nhất quán, các nhóm phụ trách sản phẩm có thể phát hiện ra tiềm năng thiết kế lớn nhất của họ.

logo_components_color_2x_web_96dp.png

Thành phần Material (MDC) giúp nhà phát triển triển khai Material Design. Được tạo bởi một nhóm các kỹ sư và nhà thiết kế trải nghiệm người dùng tại Google, MDC có nhiều thành phần giao diện người dùng đẹp mắt, dễ sử dụng và có sẵn cho Android, iOS, web và Flutter.material.io/develop

Hệ thống chuyển động của Material dành cho Android là gì?

Hệ thống chuyển động Material dành cho Android là một tập hợp các mẫu chuyển đổi trong thư viện MDC-Android có thể giúp người dùng hiểu và thao tác trong ứng dụng, như mô tả trong nguyên tắc Material Design.

Sau đây là 4 mẫu chuyển đổi chính của Material:

  • Chuyển đổi vùng chứa: chuyển đổi giữa các thành phần giao diện người dùng có chứa một vùng chứa; tạo kết nối rõ ràng giữa hai phần tử riêng biệt trên giao diện người dùng bằng cách chuyển đổi liền mạch một phần tử thành phần tử khác.
  • Trục chung: chuyển đổi giữa các thành phần giao diện người dùng có mối quan hệ về không gian hoặc điều hướng; sử dụng phép biến đổi chung trên trục x, y hoặc z để củng cố mối quan hệ giữa các phần tử.
  • Fade Through: chuyển đổi giữa các phần tử giao diện người dùng không có mối quan hệ chặt chẽ với nhau; sử dụng hiệu ứng làm mờ và hiện dần theo tuần tự theo tỷ lệ của phần tử chuyển đến.
  • Độ mờ: dùng cho các thành phần trên giao diện người dùng đi vào hoặc thoát ra trong giới hạn màn hình.

Thư viện MDC-Android cung cấp các lớp chuyển đổi cho các mô hình này, được xây dựng dựa trên cả thư viện AndroidX Transition (androidx.transition) và Khung chuyển đổi Android (android.transition):

AndroidX

  • Có trong gói com.google.android.material.transition
  • Hỗ trợ API cấp 14 trở lên
  • Hỗ trợ các Mảnh và Khung hiển thị, nhưng không hỗ trợ Hoạt động hoặc Windows
  • Chứa các bản sửa lỗi được điều chỉnh cho phiên bản cũ và hành vi nhất quán trên các cấp độ API

Khung

  • Có trong gói com.google.android.material.transition.platform
  • Hỗ trợ API cấp 21 trở lên
  • Hỗ trợ Mảnh, Khung hiển thị, Hoạt động và Windows
  • Các bản sửa lỗi không được điều chỉnh cho phiên bản cũ và có thể có hành vi khác nhau trên các cấp độ API

Trong lớp học lập trình này, bạn sẽ sử dụng hiệu ứng chuyển đổi Material được xây dựng dựa trên thư viện AndroidX, có nghĩa là bạn sẽ chủ yếu tập trung vào các Mảnh và Khung hiển thị.

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

Lớp học lập trình này sẽ hướng dẫn bạn xây dựng một số hiệu ứng chuyển đổi thành một ứng dụng email Android mẫu có tên là Trả lời bằng Kotlin, để minh hoạ cách sử dụng các hiệu ứng chuyển đổi trong thư viện MDC-Android để tuỳ chỉnh giao diện của ứng dụng.

Chúng tôi sẽ cung cấp đoạn mã khởi đầu cho ứng dụng Reply (Trả lời) và bạn sẽ kết hợp các hiệu ứng chuyển đổi Material sau đây vào ứng dụng. Bạn có thể xem ảnh GIF đã hoàn thành của lớp học lập trình dưới đây:

  • Chuyển đổi Chuyển đổi vùng chứa từ danh sách email sang trang chi tiết email
  • Chuyển đổi Chuyển đổi vùng chứa từ FAB sang trang email Compose
  • Chuyển đổi Trục Z được chia sẻ từ biểu tượng tìm kiếm sang trang chế độ xem tìm kiếm
  • Chuyển đổi Fade through (Làm mờ) giữa các trang hộp thư
  • Chuyển đổi Chuyển đổi vùng chứa từ khối địa chỉ email sang chế độ xem thẻ

Miền của iframe được yêu cầu (youtu.be) chưa được đưa vào danh sách cho phép.

Bạn cần có

  • Kiến thức cơ bản về cách phát triển cho Android và Kotlin
  • Android Studio (tải xuống tại đây nếu bạn chưa có)
  • Trình mô phỏng hoặc thiết bị Android (có trên Android Studio)
  • Mã mẫu (xem bước tiếp theo)

Bạn đánh giá mức độ kinh nghiệm xây dựng ứng dụng Android của mình ở mức nào?

Người mới tập Trung cấp Thành thạo

2. Thiết lập môi trường phát triển

Khởi động Android Studio

Khi mở Android Studio, bạn sẽ thấy cửa sổ có tiêu đề "Welcome to Android Studio" (Chào mừng bạn đến với Android Studio). Tuy nhiên, nếu đây là lần đầu tiên bạn chạy Android Studio, hãy làm theo các bước trong Android Studio Setup Wizard (Trình hướng dẫn thiết lập Android Studio) với các giá trị mặc định. Bước này có thể mất vài phút để tải xuống và cài đặt các tệp cần thiết, vì vậy hãy để ứng dụng này chạy dưới nền trong khi thực hiện phần tiếp theo.

Cách 1: Sao chép ứng dụng của lớp học lập trình khởi đầu trên GitHub

Để sao chép lớp học lập trình này từ GitHub, hãy chạy các lệnh sau:

git clone https://github.com/material-components/material-components-android-motion-codelab.git
cd material-components-android-motion-codelab

Cách 2: Tải tệp zip của ứng dụng dành cho lớp học lập trình ban đầu

Ứng dụng khởi đầu này nằm trong thư mục material-components-android-motion-codelab-develop.

Tải mã khởi đầu trong Android Studio

  1. Sau khi trình hướng dẫn thiết lập hoàn tất và cửa sổ Welcome to Android Studio (Chào mừng bạn đến với Android Studio) hiển thị, hãy nhấp vào Open an existing Android Studio project (Mở một dự án Android Studio hiện có).

e3f200327a67a53.png

  1. Chuyển đến thư mục bạn đã cài đặt mã mẫu rồi chọn thư mục mẫu để mở dự án.
  2. Đợi một chút để Android Studio tạo và đồng bộ hoá dự án, như được minh hoạ bằng các chỉ báo hoạt động ở cuối cửa sổ Android Studio.
  1. Tại thời điểm này, Android Studio có thể phát sinh một số lỗi bản dựng do bạn đang thiếu SDK Android hoặc công cụ xây dựng, chẳng hạn như lỗi hiển thị dưới đây. Làm theo hướng dẫn trong Android Studio để cài đặt/cập nhật các ứng dụng này và đồng bộ hoá dự án của bạn. Nếu bạn vẫn gặp vấn đề, hãy làm theo hướng dẫn về cách cập nhật các công cụ bằng Trình quản lý SDK.

6e026ae171f5b1eb.png.

Xác minh các phần phụ thuộc của dự án

Dự án cần phần phụ thuộc trên thư viện MADC-Android. Mã mẫu mà bạn tải xuống đã có phần phụ thuộc này được liệt kê, nhưng hãy cùng xem cấu hình để chắc chắn.

Chuyển đến tệp build.gradle của mô-đun app và đảm bảo rằng khối dependencies bao gồm một phần phụ thuộc trên MDC-Android:

implementation 'com.google.android.material:material:1.2.0'

Chạy ứng dụng khởi đầu

  1. Hãy đảm bảo cấu hình bản dựng ở bên trái lựa chọn thiết bị là app.
  2. Nhấn nút Chạy / Chạy màu xanh lục để tạo và chạy ứng dụng.

24218d0a6ae25803.pngS

  1. Trong cửa sổ Select Deployment Target (Chọn đối tượng triển khai), nếu bạn đã có thiết bị Android trong danh sách thiết bị hiện có, hãy chuyển đến Bước 8. Nếu không, hãy nhấp vào Create New Virtual Device (Tạo thiết bị ảo mới).
  2. Trên màn hình Select Hardware (Chọn phần cứng), hãy chọn một thiết bị điện thoại, chẳng hạn như Pixel 3, sau đó nhấp vào Next (Tiếp theo).
  3. Trên màn hình System Image (Hình ảnh hệ thống), hãy chọn một phiên bản Android gần đây, tốt nhất là cấp độ API cao nhất. Nếu chưa cài đặt, hãy nhấp vào đường liên kết Tải xuống xuất hiện rồi hoàn tất quá trình tải xuống.
  4. Nhấp vào Tiếp theo.
  5. Trên màn hình Android Virtual Device (AVD) (Thiết bị Android ảo (AVD)), hãy giữ nguyên chế độ cài đặt rồi nhấp vào Finish (Hoàn tất).
  6. Chọn một thiết bị Android trong hộp thoại đích triển khai.
  7. Nhấp vào Ok.
  8. Android Studio tạo ứng dụng, triển khai và tự động mở ứng dụng trên thiết bị mục tiêu.

Thành công! Mã khởi đầu cho trang chủ của Reply (Trả lời) phải chạy trong trình mô phỏng. Bạn sẽ thấy Hộp thư đến chứa danh sách các email.

cc73eb0d0f779035.png

Không bắt buộc: Làm chậm ảnh động trên thiết bị

Vì lớp học lập trình này liên quan đến các hiệu ứng chuyển đổi nhanh chóng nhưng chỉn chu, nên có thể hữu ích khi bạn làm chậm ảnh động của thiết bị để quan sát một số chi tiết rõ ràng hơn của các hiệu ứng chuyển đổi khi bạn đang triển khai. Bạn có thể thực hiện việc này bằng các lệnh shell adb hoặc Thẻ thông tin Cài đặt nhanh. Lưu ý rằng các phương pháp làm chậm ảnh động trên thiết bị này cũng sẽ ảnh hưởng đến ảnh động trên thiết bị bên ngoài ứng dụng Reply (Trả lời).

Phương pháp 1: Các lệnh shell ADB

Để làm chậm ảnh động của thiết bị theo hệ số 10 lần, bạn có thể chạy các lệnh sau từ dòng lệnh:

adb shell settings put global window_animation_scale 10
adb shell settings put global transition_animation_scale 10
adb shell settings put global animator_duration_scale 10

Để đặt lại tốc độ ảnh động của thiết bị về chế độ bình thường, hãy chạy các lệnh sau:

adb shell settings put global window_animation_scale 1
adb shell settings put global transition_animation_scale 1
adb shell settings put global animator_duration_scale 1

Phương pháp 2: Thẻ thông tin trong phần Cài đặt nhanh

Ngoài ra, để thiết lập Thẻ thông tin Cài đặt nhanh, trước tiên hãy bật chế độ Cài đặt cho nhà phát triển trên thiết bị của bạn nếu trước đó bạn chưa bật:

  1. Mở phần "Cài đặt" của thiết bị ứng dụng
  2. Cuộn xuống dưới cùng rồi nhấp vào "Giới thiệu về thiết bị được mô phỏng"
  3. Di chuyển xuống dưới cùng rồi nhấp nhanh vào "Số bản dựng" cho đến khi bật chế độ Cài đặt của nhà phát triển

Tiếp theo, hãy làm như sau, vẫn trong phần "Cài đặt" của thiết bị để bật Thẻ thông tin Cài đặt nhanh:

  1. Nhấp vào biểu tượng tìm kiếm hoặc thanh tìm kiếm ở đầu màn hình
  2. Nhập "ô" trong trường tìm kiếm
  3. Nhấp vào "Ô cài đặt nhanh dành cho nhà phát triển" hàng
  4. Nhấp vào "Window animation scale" (Tỷ lệ ảnh động cửa sổ theo tỷ lệ) công tắc

Cuối cùng, xuyên suốt lớp học lập trình này, hãy kéo ngăn thông báo hệ thống xuống từ đầu màn hình rồi sử dụng biểu tượng c7e3f98200023f6a.png để chuyển đổi giữa ảnh động tốc độ chậm và ảnh động tốc độ bình thường.

3. Làm quen với mã ứng dụng mẫu

Hãy cùng xem xét mã. Chúng tôi đã cung cấp một ứng dụng sử dụng thư viện thành phần Điều hướng Jetpack để di chuyển giữa một số Mảnh, tất cả đều nằm trong một Hoạt động duy nhất, MainActivity:

  • HomeFragment: hiển thị danh sách email
  • EmailFragment: hiển thị một email đầy đủ duy nhất
  • ComposeFragment: cho phép soạn một email mới
  • SearchFragment: hiển thị khung hiển thị tìm kiếm

Trước tiên, để tìm hiểu cách thiết lập biểu đồ điều hướng của ứng dụng, hãy mở navigation_graph.xml trong thư mục app -> src -> main -> res -> navigation:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/navigation_graph"
   app:startDestination="@id/homeFragment">

   <fragment
       android:id="@+id/homeFragment"
       android:name="com.materialstudies.reply.ui.home.HomeFragment"
       android:label="HomeFragment">
       <argument...>
       <action
           android:id="@+id/action_homeFragment_to_emailFragment"
           app:destination="@id/emailFragment" />
   </fragment>
   <fragment
       android:id="@+id/emailFragment"
       android:name="com.materialstudies.reply.ui.email.EmailFragment"
       android:label="EmailFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/composeFragment"
       android:name="com.materialstudies.reply.ui.compose.ComposeFragment"
       android:label="ComposeFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/searchFragment"
       android:name="com.materialstudies.reply.ui.search.SearchFragment"
       android:label="SearchFragment" />
   <action
       android:id="@+id/action_global_homeFragment"
       app:destination="@+id/homeFragment"
       app:launchSingleTop="true"
       app:popUpTo="@+id/navigation_graph"
       app:popUpToInclusive="true"/>
   <action
       android:id="@+id/action_global_composeFragment"
       app:destination="@+id/composeFragment" />
   <action
       android:id="@+id/action_global_searchFragment"
       app:destination="@+id/searchFragment" />
</navigation>

Hãy lưu ý đến sự hiện diện của tất cả các mảnh nêu trên, trong đó mảnh khởi chạy mặc định được đặt thành HomeFragment qua app:startDestination="@id/homeFragment". Định nghĩa XML này về biểu đồ đích đến của mảnh, cũng như các thao tác, thông báo cho mã điều hướng Kotlin đã tạo mà bạn sẽ gặp khi kết nối chuyển đổi.

activity_main.xml

Tiếp theo, hãy xem bố cục activity_main.xml trong thư mục app -> src -> main -> res -> layout. Bạn sẽ thấy NavHostFragment được định cấu hình thông qua biểu đồ điều hướng ở trên:

<fragment
   android:id="@+id/nav_host_fragment"
   android:name="androidx.navigation.fragment.NavHostFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:defaultNavHost="true"
   app:navGraph="@navigation/navigation_graph"/>

NavHostFragment này sẽ lấp đầy màn hình và xử lý mọi thay đổi về cách điều hướng mảnh toàn màn hình trong ứng dụng. BottomAppBarFloatingActionButton neo của nó, cũng trong activity_main.xml, được bố trí phía trên mảnh hiện tại do NavHostFragment hiển thị, do đó sẽ được hiện hoặc ẩn tuỳ thuộc vào đích đến của mảnh theo mã ứng dụng mẫu được cung cấp.

Ngoài ra, BottomNavDrawerFragment trong activity_main.xml là ngăn dưới cùng chứa trình đơn để điều hướng giữa các hộp thư email khác nhau, được hiển thị có điều kiện thông qua nút biểu trưng Trả lời BottomAppBar.

MainActivity.kt

Cuối cùng, để xem ví dụ về một thao tác điều hướng đang được sử dụng, hãy mở MainActivity.kt trong thư mục app -> src -> main -> java -> com.materialstudies.reply.ui. Tìm hàm navigateToSearch(), hàm này có dạng như sau:

private fun navigateToSearch() {
   val directions = SearchFragmentDirections.actionGlobalSearchFragment()
   findNavController(R.id.nav_host_fragment).navigate(directions)
}

Hình này minh hoạ cách bạn có thể điều hướng đến trang chế độ xem tìm kiếm mà không có hiệu ứng chuyển đổi tuỳ chỉnh. Trong lớp học lập trình này, bạn sẽ tìm hiểu sâu về MainActivity và 4 mảnh chính của Reply để thiết lập các lượt chuyển đổi Material hoạt động song song với các thao tác điều hướng khác nhau trên toàn ứng dụng.

Giờ bạn đã quen với mã khởi đầu, hãy triển khai hiệu ứng chuyển đổi đầu tiên.

4. Thêm hiệu ứng chuyển đổi Biến đổi vùng chứa từ danh sách email vào trang chi tiết email

Để bắt đầu, bạn sẽ thêm hiệu ứng chuyển đổi khi nhấp vào một email. Đối với thay đổi về điều hướng này, mẫu biến đổi vùng chứa là rất phù hợp, vì mẫu này được thiết kế để chuyển đổi giữa các phần tử trên giao diện người dùng có chứa vùng chứa. Mẫu này tạo ra sự kết nối rõ ràng giữa 2 thành phần trên giao diện người dùng.

Trước khi thêm mã, hãy thử chạy ứng dụng Reply (Trả lời) và nhấp vào một email. Thao tác này sẽ thực hiện một cú nhảy đơn giản, nghĩa là màn hình được thay thế mà không có hiệu ứng chuyển đổi:

f0e8a92eb2216bce.gif

Bắt đầu bằng cách thêm thuộc tính transitionName vào MaterialCardView trong email_item_layout.xml như trong đoạn mã sau:

email_item_layout.xml

android:transitionName="@{@string/email_card_transition_name(email.id)}"

Tên chuyển đổi lấy một tài nguyên chuỗi có tham số. Bạn cần sử dụng mã nhận dạng của từng email để đảm bảo mỗi transitionName trong EmailFragment là riêng biệt.

Bây giờ, bạn đã đặt tên chuyển đổi cho mục danh sách email, hãy làm tương tự trong bố cục chi tiết email. Trong fragment_email.xml, hãy đặt transitionName của MaterialCardView thành tài nguyên chuỗi sau:

fragment_email.xml

android:transitionName="@string/email_card_detail_transition_name"

Trong HomeFragment.kt, hãy thay thế mã trong onEmailClicked bằng đoạn mã dưới đây để tạo mối liên kết từ chế độ xem bắt đầu (mục danh sách email) và chế độ xem kết thúc (màn hình chi tiết về email):

HomeFragment.kt

val emailCardDetailTransitionName = getString(R.string.email_card_detail_transition_name)
val extras = FragmentNavigatorExtras(cardView to emailCardDetailTransitionName)
val directions = HomeFragmentDirections.actionHomeFragmentToEmailFragment(email.id)
findNavController().navigate(directions, extras)

Bây giờ, bạn đã định cấu hình hệ thống ống nước, bạn có thể tạo một biến đổi vùng chứa. Trong phương thức EmailFragment onCreate, hãy đặt sharedElementEnterTransition thành một thực thể mới của MaterialContainerTransform (nhập phiên bản com.google.android.material.transition trái ngược với phiên bản com.google.android.material.transition.platform) bằng cách thêm đoạn mã sau:

EmailFragment.kt

sharedElementEnterTransition = MaterialContainerTransform().apply {
   drawingViewId = R.id.nav_host_fragment
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))
}

Bây giờ, hãy thử chạy lại ứng dụng.

ed62cedec31da268.gif

Mọi thứ đang bắt đầu ổn! Khi bạn nhấp vào một email trong danh sách email, phép biến đổi vùng chứa sẽ mở rộng mục trong danh sách thành trang chi tiết toàn màn hình. Tuy nhiên, hãy lưu ý rằng việc nhấn quay lại không thu gọn email trở lại danh sách. Ngoài ra, danh sách email sẽ biến mất ngay khi bắt đầu quá trình chuyển đổi, hiển thị nền cửa sổ màu xám. Vậy chúng ta vẫn chưa xong.

Để khắc phục lỗi chuyển đổi trả về, hãy thêm hai dòng sau vào phương thức onViewCreated trong HomeFragment.kt:

HomeFragment.kt

postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }

Hãy thử chạy lại ứng dụng. Nhấn nút quay lại sau khi mở email sẽ thu gọn email đó trở lại danh sách. Tuyệt vời! Hãy tiếp tục cải thiện ảnh động.

Vấn đề về việc danh sách email biến mất là do khi điều hướng đến một Mảnh mới bằng Thành phần điều hướng, Mảnh hiện tại sẽ bị xoá ngay lập tức và được thay thế bằng Mảnh mới sắp tới. Để danh sách email vẫn hiển thị ngay cả sau khi bị thay thế, bạn có thể thêm chuyển đổi thoát vào HomeFragment.

Thêm đoạn mã dưới đây vào phương thức HomeFragment onEmailClicked để thu nhỏ danh sách email một cách tinh tế khi thoát và đăng nhập lại khi nhập lại:

HomeFragment.kt

exitTransition = MaterialElevationScale(false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Tiếp theo, để đảm bảo hiệu ứng chuyển đổi MaterialElevationScale được áp dụng cho toàn bộ màn hình chính, thay vì cho từng khung hiển thị riêng lẻ trong hệ phân cấp, hãy đánh dấu RecyclerView trong fragment_home.xml làm nhóm chuyển đổi.

fragment_home.xml

android:transitionGroup="true"

Ở giai đoạn này, bạn sẽ phải biến đổi vùng chứa hoạt động hoàn toàn. Khi nhấp vào một email, mục danh sách sẽ mở rộng sang màn hình chi tiết trong khi xem lại danh sách email. Thao tác nhấn quay lại sẽ thu gọn màn hình chi tiết email trở lại một mục danh sách trong khi vẫn mở rộng danh sách email.

9df2b39d5a150418.gif

5. Thêm hiệu ứng chuyển đổi Biến đổi vùng chứa từ FAB vào trang email Compose

Hãy tiếp tục chuyển đổi vùng chứa và thêm hiệu ứng chuyển đổi từ Nút hành động nổi sang ComposeFragment, mở rộng FAB thành một email mới do người dùng viết. Trước tiên, chạy lại ứng dụng rồi nhấp vào nút hành động nổi để đảm bảo không có hiệu ứng chuyển đổi khi khởi chạy màn hình soạn email.

d242c9708abd382c.gif

Mặc dù chúng ta sử dụng cùng một lớp chuyển đổi, nhưng cách định cấu hình thực thể này sẽ khác vì FAB nằm trong MainActivityComposeFragment được đặt bên trong vùng chứa lưu trữ điều hướng MainActivity.

Trong ComposeFragment.kt, hãy thêm đoạn mã sau vào phương thức onViewCreated, nhớ nhập phiên bản androidx.transition của Slide.

ComposeFragment.kt

enterTransition = MaterialContainerTransform().apply {
   startView = requireActivity().findViewById(R.id.fab)
   endView = emailCardView
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   containerColor = requireContext().themeColor(R.attr.colorSurface)
   startContainerColor = requireContext().themeColor(R.attr.colorSecondary)
   endContainerColor = requireContext().themeColor(R.attr.colorSurface)
}
returnTransition = Slide().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_medium).toLong()
   addTarget(R.id.email_card_view)
}

Ngoài các tham số dùng để định cấu hình biến đổi vùng chứa trước đó, startViewendView đang được thiết lập theo cách thủ công tại đây. Thay vì sử dụng các thuộc tính transitionName để cho hệ thống Android Transition biết nên chuyển đổi khung hiển thị nào, bạn có thể chỉ định khung hiển thị đó theo cách thủ công khi cần.

Bây giờ, hãy chạy lại ứng dụng. Bạn sẽ thấy nút hành động nổi chuyển đổi thành màn hình soạn thư (xem ảnh GIF ở cuối bước này).

Tương tự như bước trước, bạn cần thêm hiệu ứng chuyển đổi vào HomeFragment để lớp này không biến mất sau khi bị xoá và được thay thế bằng ComposeFragment.

Sao chép đoạn mã dưới đây vào phương thức navigateToCompose trong MainActivity trước khi gọi NavController navigate.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialElevationScale(false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialElevationScale(true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Vậy là xong! Bạn sẽ có hiệu ứng chuyển đổi từ FAB sang màn hình soạn thư như sau:

81b68391ac4b0a9.gif

6. Thêm hiệu ứng chuyển đổi Trục Z dùng chung từ biểu tượng tìm kiếm vào trang xem tìm kiếm

Trong bước này, chúng ta sẽ thêm hiệu ứng chuyển đổi từ biểu tượng tìm kiếm sang chế độ xem tìm kiếm toàn màn hình. Vì không có vùng chứa lâu dài nào liên quan đến sự thay đổi về cách điều hướng này, nên chúng ta có thể sử dụng hiệu ứng chuyển đổi Trục Z dùng chung để củng cố mối quan hệ không gian giữa hai màn hình và cho biết việc di chuyển một cấp lên trên trong hệ phân cấp của ứng dụng.

Trước khi thêm bất kỳ mã bổ sung nào, hãy thử chạy ứng dụng và nhấn vào biểu tượng tìm kiếm ở góc dưới cùng bên phải màn hình. Thao tác này sẽ làm xuất hiện màn hình chế độ xem tìm kiếm mà không có hiệu ứng chuyển đổi.

499e1a677b4216bb.gif

Để bắt đầu, hãy tìm phương thức navigateToSearch trong MainActivity rồi thêm đoạn mã sau đây trước lệnh gọi phương thức NavController navigate để thiết lập lối ra của mảnh hiện tại và nhập lại MaterialSharedAxis lượt chuyển đổi Trục Z.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Tiếp theo, hãy thêm đoạn mã sau vào phương thức onCreate trong SearchFragment để định cấu hình hiệu ứng chuyển đổi nhập và trả về MaterialSharedAxis.

SearchFragment.kt

enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Cuối cùng, để đảm bảo hiệu ứng chuyển đổi MaterialSharedAxis được áp dụng cho toàn bộ màn hình tìm kiếm, thay vì cho từng khung hiển thị riêng lẻ trong hệ phân cấp, hãy đánh dấu LinearLayout trong fragment_search.xml làm nhóm chuyển đổi.

fragment_search.xml

android:transitionGroup="true"

Vậy là xong! Bây giờ, hãy thử chạy lại ứng dụng rồi nhấn vào biểu tượng tìm kiếm. Màn hình trang chủ và màn hình chế độ xem tìm kiếm phải làm mờ và chia tỷ lệ đồng thời theo chiều sâu của trục Z, tạo ra hiệu ứng liền mạch giữa hai màn hình.

e5c0b0a130e807db.gif

7. Thêm hiệu ứng chuyển đổi mờ dần giữa các trang hộp thư

Trong bước này, chúng ta sẽ thêm hiệu ứng chuyển đổi giữa các hộp thư khác nhau. Vì không muốn nhấn mạnh mối quan hệ không gian hoặc phân cấp, chúng ta sẽ sử dụng hiệu ứng làm mờ để thực hiện một thao tác "hoán đổi" đơn giản giữa các danh sách email.

Trước khi thêm bất kỳ mã bổ sung nào, hãy thử chạy ứng dụng, nhấn vào biểu trưng Reply (Trả lời) trong Thanh ứng dụng ở dưới cùng và chuyển đổi hộp thư. Danh sách email sẽ thay đổi mà không có hiệu ứng chuyển đổi.

2c874c0a4588e8fb.gif

Để bắt đầu, hãy tìm phương thức navigateToHome trong MainActivity và thêm đoạn mã sau đây trước lệnh gọi phương thức NavController navigate để thiết lập quá trình chuyển đổi MaterialFadeThrough thoát của mảnh hiện tại.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialFadeThrough().apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Tiếp theo, hãy mở HomeFragment. Trong onCreate, hãy đặt enterTransition của mảnh thành một thực thể mới của MaterialFadeThrough.

HomeFragment.kt

enterTransition = MaterialFadeThrough().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Chạy lại ứng dụng. Khi bạn mở ngăn điều hướng ở dưới cùng và thay đổi hộp thư, danh sách email hiện tại sẽ mờ dần và thu nhỏ trong khi danh sách mới mờ dần và thu nhỏ. Tuyệt vời!

f61dfd58ea7bd3fd.gif

8. Thêm hiệu ứng chuyển đổi Vùng chứa (container Transform) từ khối địa chỉ email vào chế độ xem thẻ

Ở bước này, bạn sẽ thêm hiệu ứng chuyển đổi khối thành thẻ bật lên. Biến đổi vùng chứa được dùng ở đây để thông báo cho người dùng rằng hành động được thực hiện trong cửa sổ bật lên sẽ ảnh hưởng đến khối mà cửa sổ bật lên bắt nguồn.

Trước khi thêm bất kỳ mã nào, hãy chạy ứng dụng Reply (Trả lời), nhấp vào một email, rồi nhấp vào "trả lời" FAB rồi thử nhấp vào khối liên hệ của người nhận. Khối sẽ biến mất ngay lập tức và một thẻ có địa chỉ email của người liên hệ đó sẽ xuất hiện mà không có hoạt ảnh nào.

6200c682da2382d5.gif

Bạn sẽ thực hiện bước này trong ComposeFragment. Đã thêm vào bố cục ComposeFragment các khối người nhận (hiển thị theo mặc định) và thẻ người nhận (không hiển thị theo mặc định). Khối người nhận và thẻ này là hai chế độ xem mà bạn sẽ tạo biến đổi vùng chứa.

Để bắt đầu, hãy mở ComposeFragment rồi tìm phương thức expandChip. Phương thức này được gọi khi người dùng nhấp vào chip đã cung cấp. Thêm đoạn mã sau đây vào phía trên các dòng hoán đổi chế độ hiển thị recipientCardViewchip. Thao tác này sẽ kích hoạt biến đổi vùng chứa được đăng ký qua beginDelayedTransition.

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = chip
   endView = binding.recipientCardView
   scrimColor = Color.TRANSPARENT
   endElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(binding.recipientCardView)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

Nếu bạn chạy ứng dụng ngay bây giờ, khối sẽ biến đổi thành một thẻ chứa địa chỉ email của người nhận. Tiếp theo, hãy định cấu hình quy trình chuyển đổi trả lại để thu gọn thẻ trở lại vào chip.

Trong phương thức collapseChip trong ComposeFragment, hãy thêm đoạn mã dưới đây để thu gọn thẻ trở lại vào khối.

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = binding.recipientCardView
   endView = chip
   scrimColor = Color.TRANSPARENT
   startElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(chip)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

Chạy lại ứng dụng. Thao tác nhấp vào khối sẽ mở rộng khối này thành một thẻ, trong khi thao tác nhấp vào thẻ, thẻ đó sẽ được thu gọn trở lại vào khối. Tuyệt vời!

e823b28e2890e05d.gif

9. Đã xong

Sử dụng chưa đến 100 dòng mã Kotlin và một số mã đánh dấu XML cơ bản, thư viện MDC-Android đã giúp bạn tạo ra các hiệu ứng chuyển đổi đẹp mắt trong một ứng dụng hiện có, tuân thủ nguyên tắc Material Design, đồng thời giao diện và hoạt động nhất quán trên tất cả các thiết bị Android.

454a47ba96017a25.gif

Các bước tiếp theo

Để biết thêm thông tin về hệ thống chuyển động Material, hãy nhớ xem quy cáchtài liệu đầy đủ dành cho nhà phát triển, đồng thời thử thêm một số hiệu ứng chuyển đổi Material vào ứng dụng!

Cảm ơn bạn đã dùng thử tính năng Chuyển động Material. Chúng tôi hy vọng bạn thích lớp học lập trình này!

Tôi đã có thể hoàn thành lớp học lập trình này với khá nhiều thời gian và công sức

Hoàn toàn đồng ý Đồng ý Bình thường Không đồng ý Hoàn toàn không đồng ý

Tôi muốn tiếp tục sử dụng hệ thống chuyển động Material trong tương lai

Hoàn toàn đồng ý Đồng ý Bình thường Không đồng ý Hoàn toàn không đồng ý