理解共享元素的退出/重新进入过渡

15

我正在对Android L中的共享元素过渡进行一些基础探索。我设置了一个简单的示例,其中在活动转换期间,图像视图从屏幕顶部向底部平移,并延长了过渡持续时间,以便我可以看到它们的工作情况。尝试理解共享元素过渡的工作原理时,我遇到了两个问题。

1)仅使用Enter/Return过渡(Exit/Reenter设置为null)时。进入过渡很好,但当按下返回按钮时,视图会动画一段时间,然后停止,最后重新出现在最终位置。似乎类似于这个问题,但我已将所有Exist/Reenter转换设置为null,所以不知道为什么会发生这种情况。

2)仅使用Exit/Reenter过渡(Enter/Return设置为null)时。什么也没有发生,视图沿着默认的进入过渡(300ms持续时间)向下转换,当按下返回键时,视图会弹回到其原始位置。

如何使用Exit/Reenter过渡?

这里是我的代码:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageView"
        android:src="@drawable/ic_launcher"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Animate!"
        android:id="@+id/button"
        android:layout_centerVertical="true"
        android:layout_alignParentStart="true" />

</RelativeLayout>

activity_second.xml

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/imageView2"
    android:src="@drawable/ic_launcher"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true" />

MainActivity.java

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
        getWindow().setAllowEnterTransitionOverlap(false);
        getWindow().setAllowReturnTransitionOverlap(false);


        getWindow().setSharedElementExitTransition(exitTransition());
        getWindow().setSharedElementReenterTransition(reenterTransition());
        //getWindow().setSharedElementExitTransition(null);
        //getWindow().setSharedElementReenterTransition(null);


        setContentView(R.layout.activity_main);

        final View iView = findViewById(R.id.imageView);
        iView.setTransitionName("image");

        final Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                ActivityOptions options = ActivityOptions
                        .makeSceneTransitionAnimation(MainActivity.this, iView, "image");
                startActivity(intent, options.toBundle());
            }
        });
    }

    private Transition exitTransition() {
        ChangeBounds bounds = new ChangeBounds();
        bounds.setInterpolator(new BounceInterpolator());
        bounds.setDuration(2000);

        return bounds;
    }

    private Transition reenterTransition() {
        ChangeBounds bounds = new ChangeBounds();
        bounds.setInterpolator(new OvershootInterpolator());
        bounds.setDuration(2000);

        return bounds;
    }
}

SecondActivity.java

public class SecondActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
        getWindow().setAllowEnterTransitionOverlap(false);
        getWindow().setAllowReturnTransitionOverlap(false);


        //getWindow().setSharedElementEnterTransition(enterTransition());
        //getWindow().setSharedElementReturnTransition(returnTransition());
        getWindow().setSharedElementEnterTransition(null);
        getWindow().setSharedElementReturnTransition(null);


        setContentView(R.layout.activity_second);

        final View iView = findViewById(R.id.imageView2);
        iView.setTransitionName("image");
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        finishAfterTransition();
    }

    private Transition enterTransition() {
        ChangeBounds bounds = new ChangeBounds();
        bounds.setDuration(2000);

        return bounds;
    }

    private Transition returnTransition() {
        ChangeBounds bounds = new ChangeBounds();
        bounds.setInterpolator(new DecelerateInterpolator());
        bounds.setDuration(2000);

        return bounds;
    }
}
2个回答

13
  1. onBackPressed()方法中不应该调用finishAfterTransition()Activity父类已经为您执行了此操作。

  2. 您应该在super.onCreate()之前调用requestFeature()方法。如果您正在使用Theme.Material主题(或类似主题),则不需要请求Window.FEATURE_ACTIVITY_TRANSITIONS

  3. 在这里调用setAllowEnterTransitionOverlap(false)setAllowReturnTransitionOverlap(false)是多余的。这些参数确定活动的窗口内容转换是否重叠...它们根本不会影响活动的共享元素内容转换。

  4. 设置退出和重新进入共享元素转换很少有必要。您几乎总是希望使用进入和返回转换。如果您仅设置退出和重新进入共享元素转换并将进入和返回共享元素转换保留为空,则被调用的活动将无法知道如何在过渡开始时对共享元素进行动画处理,动画看起来会出现问题。


那么什么样的情况下我会想要使用退出/重新进入转换的示例呢?编辑:我按照您的建议进行了操作,但看起来动画返回仍然有些不稳定。 - user2100277
1
我还没有找到使用退出/重新进入过渡的好理由...事实上,它们甚至不适用于Fragment转换。也许其他人可以给出一个好的答案... - Alex Lockwood
1
嗨@AlexLockwood,你能否看一下我几周前发布的一个问题,关于在启用转换时将活动带到活动堆栈的前面?提前致谢。 http://stackoverflow.com/questions/31295598/lollipop-transitions-not-working-when-resuming-activity - GonzoBongo

9
据我回忆,在L版本中存在一个bug,如果共享元素返回转场所需的时间超过重新进入转场的持续时间,则会导致其被中断。如果您调整重新进入转场(在调用Activity上),那么可以解决中断问题,直到MR1中修复此bug。
退出和重新进入转场是为了在允许共享元素进行转换之前执行一些操作。例如,如果您想在传输共享元素之前提高它的高度,那么应该在共享元素退出转场中完成。重新进入转场将用于执行相反的操作-在视图被传输回来后放下视图。大多数应用程序不需要它,但是对于需要的罕见应用程序而言,这是有意义的。

我有几个后续问题。(1) MR1是指版本5.0.1还是之后的其他版本?(2) 为什么退出/重新进入共享元素转换适用于Activity转换,但不适用于Fragment转换? - Alex Lockwood
(1) MR1尚未发布。我不确定它将有哪个版本。 (2) 是的!片段转换是由某种移除(隐藏/分离/删除/替换)和某种添加(显示/附加/添加/替换)触发的。当您执行FragmentTransaction时,您不能同时对Fragment进行操作以触发共享元素退出转换并将其删除。 - George Mount
2
顺便提一下,我刚刚添加了一篇博客文章来描述这些。https://halfthought.wordpress.com/2014/12/08/what-are-all-these-dang-transitions/ - George Mount
1
很酷,感谢您的帖子!顺便说一句,我也正在撰写自己的博客文章,从这篇文章开始。 :) - Alex Lockwood
@GeorgeMount 我正在使用ActivityOptionsCompat,仍然遇到相同的问题,有什么建议吗? - ingsaurabh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接