Android Shared Element Transition cho Photo app – phần 1

Level 0 – Shared Element Cơ bản

Bật cờ windowContentTransition cho cả ứng dụng trong styles.xml:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
	<!-- Transition -->
        <item name="android:windowContentTransitions" tools:targetApi="21">true</item>
        <item name="android:windowEnterTransition" tools:targetApi="21">@android:transition/fade
        </item>
        <item name="android:windowExitTransition" tools:targetApi="21">@android:transition/fade
        </item>
        <item name="android:windowSharedElementEnterTransition" tools:targetApi="21">
            @android:transition/move
        </item>
        <item name="android:windowSharedElementExitTransition" tools:targetApi="21">
            @android:transition/move
	</item>
</style>

Set style cho application

<!-- Other Manifesh definitions -->
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
	
	<!-- Activity definitions -->        
</application>

Set transitionName cho view cần share ở cả 2 layout

<ImageView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:transitionName="share_poster"
    android:scaleType="centerCrop"/>

hoặc set từ code:

ViewCompat.setTransitionName(mImageView, "share_poster");

Tạo 1 SceneTransition khi bắt đầu chuyển startActivity

Intent intent = new Intent(mCurrentActivity, NewActivity.class);
        ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
                mCurrentActivity, mSharedView, ViewCompat.getTransitionName(mSharedView));
mCurrentActivity.startActivity(intent, options.toBundle());

Nếu muốn shared nhiều View cùng lúc, ta kết hợp dùng với class Pair<A, B>:

Config như vậy là đủ để share View từ Activity này sang Activity khác. Bao gồm cả return Transition khi back về activity trước

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mCurrentActivity,
        Pair.create(mView1, ViewCompat.getTransitionName(mView1)),
        Pair.create(mView2, ViewCompat.getTransitionName(mView2))
);

Căn bản về cách hoạt động:

Khi Activity 2 hoàn tất onCreate, hệ thống sẽ tìm các view với transitionName ở activity nguồn và activity đích, tính toán vị trí kích thước để tạo 1 Animation phù hợp.

View được share sẽ chạy animation trên lớp ViewOverlay tới trạng thái đích và nhường chỗ cho View ở Activity2. View ở Activity 2 sẽ tạm thời bị ẩn cho đến khi shared animation kết thúc.

Shared Animation là 1 bộ phức tạp gồm:

  • Animation thay đổi kích thước (changeBounds)
  • Animation thay đổi vị trí (changeTransform)
  • Animation thay đổi hình dáng (changeClipBounds)
  • Animation thay đổi hình ảnh (changeImageTransform), giúp thay đổi thuộc tính scaleType đối với ImageView

Lưu ý:

Bạn chú ý khi bắt đầu dùng Shared Element:

  • Không set android:windowBackground = “@null” vì sẽ khiến ViewOverlay trống để lộ ra nhiều “ảnh ảo” trong quá trình ảnh di chuyển (không tin bạn cứ test thử, cũng chả biết gọi hiệu ứng đó là gì :D).
  • Không set clipChildren=”false” và “clipToPadding=”false” cho container của ImageView nếu ImageView đang được set scaleType. Khi đó trước khi bắt đầu animation, ảnh sẽ hiện “nguyên hình” với kích thước thật.
  • Không dùng các loại crop, transform, animation, resize được support từ các thư viện load ảnh như Glide, Picasso… Chỉ được dùng thuộc tính scaleType chính chủ hoặc điều chỉnh kích thước bằng cách custom onMeasure().

Phần 2 Ta sẽ điều chỉnh phức tạp hơn với 1 RecyclerView share với 1 View

 Phần 2 – Share Element Level 1

Full demo app

2 thoughts to “Android Shared Element Transition cho Photo app – phần 1”

  1. Chào bạn!
    Cho mình hỏi 1 chút. Mình có làm thử thì khi click vào tấm hình nó nhảy sang trang detail và show tấm hình lớn luôn mà không có animation phóng to lên. Mình làm thử trên 1 project mới thì ok. Không biết cái project cũ mình đang làm có vấn đề gì ở config không?

    1. Chào bạn!
      Khi chuyển sang project mới là bạn code lại từ đầu hay dùng lại code cũ? Có nhiều nguyên nhân để animation không chạy: do config thiếu, do không giống transitionName, do ảnh chưa load kịp, do gọi sai hàm… Nếu các config đã đủ nhưng animation vẫn chưa chạy thì thường là do ảnh chưa load kịp, do bạn load ảnh từ remote, hoặc dùng các thư viện Glide, Picasso để load nên hình ảnh hiển thị bị delay.

Leave a Reply

Your email address will not be published. Required fields are marked *