MotionLayout
là một loại bố cục giúp bạn quản lý ảnh động chuyển động và tiện ích trong ứng dụng của mình. MotionLayout
là một lớp con của ConstraintLayout
và được xây dựng dựa trên các tính năng bố cục phong phú. Là một phần của thư viện ConstraintLayout
, MotionLayout
được cung cấp dưới dạng thư viện hỗ trợ.
MotionLayout
là cầu nối giữa việc chuyển đổi bố cục và xử lý chuyển động phức tạp, cung cấp sự kết hợp các tính năng giữa khung ảnh động thuộc tính, TransitionManager
và CoordinatorLayout
.
Ngoài việc mô tả hiệu ứng chuyển đổi giữa các bố cục, MotionLayout
còn cho phép bạn tạo ảnh động cho bất kỳ thuộc tính bố cục nào. Hơn nữa, nó vốn hỗ trợ các hiệu ứng chuyển đổi có thể tìm kiếm. Điều này có nghĩa là bạn có thể hiển thị ngay lập tức bất kỳ điểm nào trong hiệu ứng chuyển đổi dựa trên một số điều kiện, chẳng hạn như nhập bằng cách chạm. MotionLayout
cũng hỗ trợ các khung hình chính, cho phép các hiệu ứng chuyển đổi được tuỳ chỉnh hoàn toàn cho phù hợp với nhu cầu của bạn.
MotionLayout
mang tính khai báo đầy đủ, nghĩa là bạn có thể mô tả mọi quá trình chuyển đổi trong XML, bất kể phức tạp đến đâu.
Những điều cần lưu ý khi thiết kế
MotionLayout
dùng để di chuyển, đổi kích thước và tạo ảnh động cho các phần tử trên giao diện người dùng mà người dùng có thể tương tác, chẳng hạn như các nút và thanh tiêu đề. Đừng sử dụng chuyển động trong ứng dụng như một hiệu ứng đặc biệt vô cớ. Hãy sử dụng báo cáo này để giúp người dùng hiểu ứng dụng của bạn đang làm gì. Để biết thêm thông tin về cách thiết kế ứng dụng bằng chuyển động, hãy xem phần Tìm hiểu về chuyển động trong Material Design.
Bắt đầu
Làm theo các bước sau để bắt đầu sử dụng MotionLayout
trong dự án.
-
Thêm phần phụ thuộc
ConstraintLayout
: để sử dụngMotionLayout
trong dự án, hãy thêm phần phụ thuộcConstraintLayout
2.0 vào tệpbuild.gradle
của ứng dụng. Nếu bạn đang dùng AndroidX, hãy thêm phần phụ thuộc sau:Groovy
dependencies { implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha07" // To use constraintlayout in compose implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha07" }
Kotlin
dependencies { implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha07") // To use constraintlayout in compose implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha07") }
-
Tạo tệp
MotionLayout
:MotionLayout
là lớp con củaConstraintLayout
, vì vậy, bạn có thể chuyển đổi mọiConstraintLayout
hiện có thànhMotionLayout
bằng cách thay thế tên lớp trong tệp tài nguyên bố cục, như minh họa trong ví dụ sau:AndroidX
<!-- before: ConstraintLayout --> <androidx.constraintlayout.widget.ConstraintLayout .../> <!-- after: MotionLayout --> <androidx.constraintlayout.motion.widget.MotionLayout .../>
Thư viện hỗ trợ
<!-- before: ConstraintLayout --> <android.support.constraint.ConstraintLayout .../> <!-- after: MotionLayout --> <android.support.constraint.motion.MotionLayout .../>
Dưới đây là ví dụ đầy đủ về tệp
MotionLayout
. Tệp này xác định bố cục như trong hình 1:AndroidX
<?xml version="1.0" encoding="utf-8"?> <!-- activity_main.xml --> <androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/motionLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/scene_01" tools:showPaths="true"> <View android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:background="@color/colorAccent" android:text="Button" /> </androidx.constraintlayout.motion.widget.MotionLayout>
Thư viện hỗ trợ
<?xml version="1.0" encoding="utf-8"?> <!-- activity_main.xml --> <android.support.constraint.motion.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/motionLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/scene_01" tools:showPaths="true"> <View android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:background="@color/colorAccent" android:text="Button" /> </android.support.constraint.motion.MotionLayout>
-
Tạo MotionScene: trong ví dụ về
MotionLayout
trước, thuộc tínhapp:layoutDescription
tham chiếu đến một cảnh chuyển động. Cảnh chuyển động là một tệp tài nguyên XML. Trong phần tử gốc<MotionScene>
, một cảnh chuyển động chứa tất cả nội dung mô tả chuyển động cho bố cục tương ứng. Để tách biệt thông tin bố cục với nội dung mô tả chuyển động, mỗiMotionLayout
sẽ tham chiếu đến một cảnh chuyển động riêng. Các định nghĩa trong cảnh chuyển động được ưu tiên hơn mọi định nghĩa tương tự trongMotionLayout
.Dưới đây là tệp cảnh chuyển động mẫu mô tả chuyển động ngang cơ bản trong hình 1:
<?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000"> <OnSwipe motion:touchAnchorId="@+id/button" motion:touchAnchorSide="right" motion:dragDirection="dragRight" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> </MotionScene>
Xin lưu ý những điều sau:
-
<Transition>
chứa định nghĩa cơ sở của chuyển động.-
motion:constraintSetStart
vàmotion:constraintSetEnd
là các tham chiếu đến các điểm cuối của chuyển động. Các điểm cuối này được xác định trong các phần tử<ConstraintSet>
ở phần sau của cảnh chuyển động. -
motion:duration
chỉ định số mili giây để chuyển động hoàn tất.
-
-
<OnSwipe>
cho phép bạn tạo chế độ điều khiển cảm ứng cho chuyển động.-
motion:touchAnchorId
đề cập đến thành phần hiển thị mà người dùng có thể vuốt và kéo. -
motion:touchAnchorSide
có nghĩa là thành phần hiển thị đang được kéo từ bên phải. -
motion:dragDirection
đề cập đến hướng tiến trình của thao tác kéo. Ví dụ:motion:dragDirection="dragRight"
có nghĩa là tiến trình sẽ tăng lên khi khung hiển thị được kéo sang phải.
-
-
<ConstraintSet>
là nơi bạn xác định các quy tắc ràng buộc mô tả chuyển động của mình. Trong ví dụ này, một<ConstraintSet>
được xác định cho mỗi điểm cuối của chuyển động. Các điểm cuối này được căn giữa theo chiều dọc bằngapp:layout_constraintTop_toTopOf="parent"
vàapp:layout_constraintBottom_toBottomOf="parent"
. Theo chiều ngang, các điểm cuối nằm ở phía xa bên trái và bên phải màn hình.
Để biết thông tin chi tiết hơn về các phần tử mà cảnh chuyển động hỗ trợ, hãy xem các ví dụ về MotionLayout.
-
Thuộc tính nội suy
Trong tệp cảnh chuyển động, các phần tử ConstraintSet
có thể chứa các thuộc tính bổ sung được nội suy trong quá trình chuyển đổi. Ngoài vị trí và giới hạn, các thuộc tính sau đây còn được nội suy bằng MotionLayout
:
alpha
visibility
elevation
rotation
,rotationX
,rotationY
translationX
,translationY
,translationZ
scaleX
,scaleY
Thuộc tính tùy chỉnh
Trong <Constraint>
, bạn có thể sử dụng phần tử <CustomAttribute>
để chỉ định hiệu ứng chuyển đổi cho các thuộc tính không chỉ liên quan đến vị trí hoặc các thuộc tính View
.
<Constraint android:id="@+id/button" ...> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/> </Constraint>
<CustomAttribute>
chứa hai thuộc tính riêng:
motion:attributeName
là bắt buộc và phải khớp với một đối tượng bằng phương thức getter và setter. Phương thức getter và setter phải khớp với một mẫu cụ thể. Ví dụ:backgroundColor
được hỗ trợ vì thành phần hiển thị này có các phương thứcgetBackgroundColor()
vàsetBackgroundColor()
cơ bản.- Thuộc tính còn lại mà bạn phải cung cấp dựa trên loại giá trị. Chọn trong số các loại được hỗ trợ sau:
motion:customColorValue
cho màu sắcmotion:customIntegerValue
cho số nguyênmotion:customFloatValue
cho phao nổimotion:customStringValue
cho chuỗimotion:customDimension
cho các phương diệnmotion:customBoolean
cho giá trị boolean
Khi chỉ định một thuộc tính tuỳ chỉnh, hãy xác định các giá trị điểm cuối ở cả phần tử <ConstraintSet>
bắt đầu và kết thúc.
Thay đổi màu nền
Dựa trên ví dụ trước, giả sử bạn muốn màu của khung hiển thị thay đổi như một phần trong chuyển động của khung hiển thị, như minh hoạ trong hình 2.
Thêm một phần tử <CustomAttribute>
vào mỗi phần tử ConstraintSet
, như minh hoạ trong đoạn mã sau đây:
<ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#9999FF" /> </Constraint> </ConstraintSet>
Các thuộc tính MotionLayout khác
Ngoài các thuộc tính trong ví dụ trước, MotionLayout
còn có các thuộc tính khác mà bạn nên chỉ định:
app:applyMotionScene="boolean"
cho biết có áp dụng cảnh chuyển động hay không. Giá trị mặc định của thuộc tính này làtrue
.app:showPaths="boolean"
cho biết liệu có hiển thị các đường dẫn chuyển động khi chuyển động đang chạy hay không. Giá trị mặc định của thuộc tính này làfalse
.app:progress="float"
cho phép bạn chỉ định rõ tiến trình chuyển đổi. Bạn có thể sử dụng giá trị dấu phẩy động bất kỳ từ0
(điểm bắt đầu của quá trình chuyển đổi) đến1
(kết thúc quá trình chuyển đổi).app:currentState="reference"
cho phép bạn chỉ định mộtConstraintSet
cụ thể.app:motionDebug
cho phép bạn hiển thị thông tin gỡ lỗi bổ sung về chuyển động. Giá trị có thể là"SHOW_PROGRESS"
,"SHOW_PATH"
hoặc"SHOW_ALL"
.
Tài nguyên khác
Để biết thêm thông tin về MotionLayout
, hãy xem các tài nguyên sau:
- Android nâng cao trong Kotlin 03.2: Ảnh động với MotionLayout
- Ví dụ về MotionLayout
- MotionLayout/ConstraintLayout Samples trên GitHub
- Giới thiệu về MotionLayout (phần I)
- Giới thiệu về MotionLayout (phần II)
- Giới thiệu về MotionLayout (phần III)
- Giới thiệu về MotionLayout (phần IV)