Quản lý ảnh động chuyển động và tiện ích bằng MotionLayout

MotionLayout là 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. MotionLayout là lớp con của ConstraintLayout và được xây dựng dựa trên khả năng bố cục. Nằm trong thư viện ConstraintLayout, MotionLayout có sẵn dưới dạng thư viện hỗ trợ.

MotionLayout thu hẹp khoảng cách giữa chuyển đổi bố cục và chuyển động phức tạp cung cấp một kết hợp các tính năng giữa ảnh động thuộc tính khung, TransitionManagerCoordinatorLayout.

Hình 1. Chuyển động cơ bản có điều khiển bằng cách chạm.

Ngoài việc mô tả quá trình chuyển đổi giữa các bố cục, MotionLayout còn cho phép bạn tạo ảnh động cho mọi thuộc tính bố cục. Hơn nữa, nền tảng này vốn hỗ trợ những người có thể tìm kiếm hiệu ứng chuyển cảnh. Điều này có nghĩa là bạn có thể hiển thị ngay 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ợ khung hình chính, bật các hiệu ứng chuyển cảnh đượ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 hiệu ứng chuyển đổi trong XML, bất kể phức tạp đến mức nào.

Cân nhắc về 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à mà người dùng tương tác, chẳng hạn như nút và thanh tiêu đề. Không dùng chuyển động trong ứng dụng làm một hiệu ứng đặc biệt vô cớ. Hãy sử dụng thông tin đó để giúp người dùng hiểu được ứng dụng của bạn là gì đang làm. Để biết thêm thông tin về cách thiết kế ứng dụng bằng chuyển động, hãy xem Mục Tìm hiểu về Material Design chuyển động.

Bắt đầu

Hãy làm theo các bước sau để bắt đầu sử dụng MotionLayout trong dự án của bạn.

  1. Thêm phần phụ thuộc ConstraintLayout: để sử dụng MotionLayout trong dự án của bạn, hãy thêm Phần phụ thuộc ConstraintLayout 2.0 vào ứng dụng của bạn build.gradle. Nếu bạn đang sử dụng AndroidX, hãy thêm phần phụ thuộc sau:

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha14"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha14"
    }
    

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha14")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha14")
    }
    
  2. Tạo tệp MotionLayout: MotionLayout là lớp con của ConstraintLayout, nên bạn có thể biến đổi bất kỳ ConstraintLayout hiện tại vào MotionLayout bằng cách thay thế tên lớp trong tệp tài nguyên bố cục, như minh hoạ trong các 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à một ví dụ đầy đủ về tệp MotionLayout 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>
            
  3. Tạo MotionScene: trong MotionLayout trước Ví dụ: thuộc tính app:layoutDescription tham chiếu đến cảnh chuyển động. Cảnh chuyển động là một tệp tài nguyên XML. Bên trong <MotionScene> phần tử gốc, cảnh chuyển động chứa tất cả các mô tả chuyển động cho bố cục tương ứng. Để tách biệt thông tin bố cục với chuyển động phần mô tả, mỗi MotionLayout tham chiếu đến một chuyển động riêng cảnh. 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ự định nghĩa trong MotionLayout.

    Dưới đây là tệp cảnh chuyển động mẫu mô tả chiều ngang cơ bản chuyển động 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:constraintSetStartmotion: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 trong cảnh chuyển động.

      • motion:duration chỉ định số mili giây cần thiết để hoàn tất chuyển động.

    • <OnSwipe> cho phép bạn tạo điều khiển cảm ứng cho chuyển động.

      • motion:touchAnchorId đề cập đến chế độ xem mà người dùng có thể vuốt và kéo.

      • motion:touchAnchorSide có nghĩa là chế độ xem đang được kéo từ phía bên phải.

      • motion:dragDirection đề cập đến tiến trình hướng kéo. Ví dụ: motion:dragDirection="dragRight" nghĩa là tiến trình sẽ tăng lên khi chế độ xem được kéo sang phải.

    • <ConstraintSet> là nơi bạn xác định nhiều hạn chế mô tả chuyển động. Trong ví dụ này, một <ConstraintSet> được xác định cho từng đ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 sử dụng app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent" Theo chiều ngang, các điểm cuối nằm ở phía ngoài cùng bên trái và bên phải của màn hình.

    Để có cái nhìn chi tiết hơn về các yếu tố khác nhau trong một cảnh chuyển động hỗ trợ, hãy xem Ví dụ về MotionLayout.

Thuộc tính nội suy

Trong một tệp cảnh chuyển động, các phần tử ConstraintSet có thể chứa thông tin bổ sung được nội suy trong quá trình chuyển đổi. Ngoài vị trí và thì các thuộc tính sau sẽ được nội suy bởi 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ể dùng phần tử <CustomAttribute> để chỉ định chuyển đổi cho các thuộc tính không chỉ liên quan đến vị trí hoặc 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 có phương thức getter và phương thức setter. Phương thức getter và setter phải khớp với một mẫu cụ thể. Cho Ví dụ: backgroundColor được hỗ trợ, vì thành phần hiển thị có cơ sở Phương thức getBackgroundColor()setBackgroundColor().
  • 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 từ các loại được hỗ trợ sau:
    • motion:customColorValue cho màu
    • motion:customIntegerValue cho số nguyên
    • motion:customFloatValue cho số thực
    • motion:customStringValue cho chuỗi
    • motion:customDimension cho phương diện
    • motion:customBoolean cho boolean

Khi chỉ định thuộc tính tuỳ chỉnh, hãy xác định giá trị điểm cuối ở cả điểm bắt đầu và kết thúc phần tử <ConstraintSet>.

Thay đổi màu nền

Dựa trên ví dụ trước, giả sử bạn muốn thay đổi màu của chế độ xem như một phần của chuyển động, như minh hoạ trong hình 2.

Hình 2. Khung hiển thị sẽ thay đổi màu nền khi di chuyển.

Thêm một phần tử <CustomAttribute> vào mỗi phần tử ConstraintSet, như minh hoạ trong đoạn mã sau:

<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 bổ sung

Ngoài các thuộc tính trong ví dụ trước, MotionLayout có các thuộc tính khác mà bạn có thể muố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 chuyển động dưới dạng chuyển động đang chạy. 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 bất kỳ giá trị dấu phẩy động nào từ 0 (bắt đầu chuyển đổi) đến 1 (kết thúc quá trình chuyển đổi).
  • app:currentState="reference" cho phép bạn chỉ định một ConstraintSet cụ thể.
  • app:motionDebug cho phép bạn hiển thị thêm thông tin gỡ lỗi về chuyển động. Các 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: