12/08/2018, 14:01

Shared Element Activity Transition

Tổng quan Thông thường, việc chuyển tiếp giữa các Activiy hay Fragment chỉ đơn thuần là ẩn các Activity/Fragment cũ đi và hiển thị cái mới lên, có thể kèm theo một số hiệu ứng như Activity/Fragment mới dần dần hiện ra ( Fade), trượt vào đè lên cái cũ ( Slide).... Hiệu ứng mặc định khi chuyển ...

Tổng quan

Thông thường, việc chuyển tiếp giữa các Activiy hay Fragment chỉ đơn thuần là ẩn các Activity/Fragment cũ đi và hiển thị cái mới lên, có thể kèm theo một số hiệu ứng như Activity/Fragment mới dần dần hiện ra ( Fade), trượt vào đè lên cái cũ ( Slide)....

Hiệu ứng mặc định khi chuyển Activity:

alt

Tuy nhiên, có những trường hợp mà một phần tử xuất hiện ở cả hai Activity/Fragment cũ và mới, và việc share chúng khi chuyển tiếp sẽ tạo cho người dùng cảm giác nối tiếp giữa cái cũ và cái mới.

alt

Việc chuyển tiếp kiểu này cũng khiến cho mắt người cảm thấy mượt mà, liền mạch hơn.

altalt

Shared Elements Transition với Activity

Cần lưu ý là Shared Elements Transition chỉ hoạt động với Android 5.0 ( API level 21) trở lên và sẽ bị mặc định bỏ qua với các API level thấp hơn.

1. Thêm Window Content Transitions

Thêm Window Content Transitions vào file styles.xml:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowContentTransitions">true</item>
    ...
</style>

2. Gán chung một Transition Name

Sử dụng android:transitionName để gán một Transition Name chung cho phần tử cần share ở cả 2 layout.

Ví dụ ở MainActivity.xml:

<android.support.v7.widget.CardView
  ...>
      <ImageView
          android:id="@+id/ivProfile"
          android:transitionName="profile"
          android:scaleType="centerCrop"
          android:layout_awidth="match_parent"
          android:layout_height="160dp" />
      ...
</android.support.v7.widget.CardView>

Và ở DetailActivity.xml:

<LinearLayout
  ...>
      <ImageView
          android:id="@+id/ivProfile"
          android:transitionName="profile"
          android:scaleType="centerCrop"
          android:layout_awidth="match_parent"
          android:layout_height="380dp" />
      ...
</LinearLayout>

Start Activity

Start activity đối tượng và truyền cho nó một Bundle của những phần tử cần share.

Intent intent = new Intent(this, DetailsActivity.class);
intent.putExtra(DetailsActivity.EXTRA_CONTACT, contact);
ActivityOptionsCompat options = ActivityOptionsCompat.
    makeSceneTransitionAnimation(this, (View)ivProfile, "profile");
startActivity(intent, options.toBundle());

Để đảo ngược lại hiệu ứng chuyển tiếp khi tắt layout thứ hai, ta dùng Activity.supportFinishAfterTransition() thay vì Activity.finish().

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            supportFinishAfterTransition();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

4. Share nhiều phần tử

Ta cũng có thể tạo hiệu ứng như vậy với nhiều phần tử trong một layout. Cách làm khá đơn giản, chỉ cần gán Transition Name khác nhau cho chúng và một ít code tương tự như sau:

Intent intent = new Intent(context, DetailsActivity.class);
intent.putExtra(DetailsActivity.EXTRA_CONTACT, contact);
Pair<View, String> p1 = Pair.create((View)ivProfile, "profile");
Pair<View, String> p2 = Pair.create(vPalette, "palette");
Pair<View, String> p3 = Pair.create((View)tvName, "text");
ActivityOptionsCompat options = ActivityOptionsCompat.
    makeSceneTransitionAnimation(this, p1, p2, p3);
startActivity(intent, options.toBundle());

Lưu ý: nhớ chọn import là android.support.v4.util.Pair thay vì android.util.Pair.

Shared Elements Transition với Fragment

Cách làm cũng khá tương tự như trên.

1. Gán chung một Transition Name

<android.support.v7.widget.CardView
  ...>
      <ImageView
          android:id="@+id/ivProfile"
          android:transitionName="profile"
          android:scaleType="centerCrop"
          android:layout_awidth="match_parent"
          android:layout_height="160dp" />
      ...
</android.support.v7.widget.CardView>

2. Tạo ra Transition

Tạo thêm một transition tên change_image_transform.xml trong folder res/transition:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeImageTransform />
</transitionSet>

3. Tạo hiệu ứng chuyển tiếp trong FragmentTransaction

// Tạo thực thể của mỗi fragment
FirstFragment fragmentOne = ...;
SecondFragment fragmentTwo = ...;
// Kiểm tra xem có phải phiên bản 5.0 trở lên ko.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Inflate transitions
    Transition changeTransform = TransitionInflater.from(this).
          inflateTransition(R.transition.change_image_transform);
    Transition explodeTransform = TransitionInflater.from(this).
          inflateTransition(android.R.transition.explode);

    // Cài đặt hiệu ứng chuyển tiếp khi thoát khỏi fragment thứ nhất
    fragmentOne.setSharedElementReturnTransition(changeTransform);
    fragmentOne.setExitTransition(explodeTransform);

    // Cài đặt hiệu ứng chuyển tiếp khi bật fragment thứ hai
    fragmentTwo.setSharedElementEnterTransition(changeTransform);
    fragmentTwo.setEnterTransition(explodeTransform);

    // Phần tử cần share ở fragment thứ nhất
    ImageView ivProfile = (ImageView) findViewById(R.id.ivProfile);

    // Replace fragment thứ hai
    FragmentTransaction ft = getFragmentManager().beginTransaction()
            .replace(R.id.container, fragmentTwo)
            .addToBackStack("transaction")
            .addSharedElement(ivProfile, "profile");
    // Apply transaction
    ft.commit();
}
else {
    // Code để chạy trên các phiên bản thấp hơn
}

Một số nguồn khác để tham khảo thêm về Shared Element Transition.

  • Fragment Transitions Detailed Tutorial
  • Android Authority article
  • Fragment transitions with shared elements
  • Repo với code mẫu
  • Một vài code mẫu

Nguồn: Codepath

0