安卓启动画面到主界面的共享元素过渡

8

我的应用程序在显示主活动之前会显示一个启动画面,持续1秒钟。启动画面和主活动共享一个图像,需要从启动画面的中心动画到主活动布局的顶部。

如果将启动画面实现为主活动中的<layer-list>背景图像(参见正确的启动画面如何制作启动画面?),那么如何实现这种动画就不是很明显了。因此,我决定将启动画面实现为普通活动,并使用共享元素转换来在两个活动之间动画显示该图像。最初,我在启动活动中使用了以下onCreate()实现:

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);

        ImageView imageView = (ImageView)findViewById(R.id.imageView);
        String transitionName = ViewCompat.getTransitionName(imageView);
        Intent intent = new Intent(this, LoginActivity.class);
        ActivityOptionsCompat options =
                ActivityOptionsCompat.makeSceneTransitionAnimation(
                        this, imageView, transitionName);

        imageView.postDelayed(() -> {
            ActivityCompat.startActivity(SplashActivity.this, intent, options.toBundle());
            finish();
        }, 1000);
    }
}

这种方式存在两个问题:
  1. 在调用startActivity()后立即调用finish()会导致闪屏活动窗口在动画开始之前隐藏/销毁,这会导致主屏幕在动画期间短暂闪现。
  2. 从主活动返回时,自动触发共享元素返回转换,在主活动窗口关闭后的500毫秒内,图像似乎悬浮在主屏幕上。返回转换失败,因为闪屏活动已经调用了finish(),因此不再在返回栈中。
要解决第一个问题,我将finish()调用包装在postDelay() Runnable中,以确保它只在共享元素转换完成后才被调用。 1500ms延迟适用于我的应用程序,但该值应根据其他用例所需的时间进行调整。
...

imageView.postDelayed(() -> {
    ActivityCompat.startActivity(SplashActivity.this, intent, options.toBundle());
    imageView.postDelayed(this::finish, 1500);
}, 1000);

为了解决第二个问题,我重写了主活动的 onBackPressed() 方法,直接调用 finish(),从而避免了默认实现中对 finishAfterTransitions() 的调用。这可以防止活动尝试执行共享元素返回转换。
@Override
public void onBackPressed() {
    finish();
}

任何改进此解决方案的替代方法或建议将不胜感激。

在延迟时间结束之前,如果用户按下返回按钮,请不要忘记删除“Runnable”。 - ARiF
3个回答

1

我也遇到过类似的问题。

一种方法是在启动画面中不调用finish(),在下一个画面中在onBackPressed()中调用finishAffinity()


0

不要使用 finish();,而是使用 ActivityCompat.finishAfterTransition(this);


2
如果您建议将主活动的finish()更改为finishAfterTransition,那么框架将尝试返回到不再存在(已完成)的启动屏幕活动,并且共享元素图像将在应用程序关闭之前停留在视图中一段时间。如果您建议更改启动屏幕活动的postDelayed调用中的finish(),则没有必要这样做,因为finishAfterTransition()仅在活动经历了先前的进入转换时才起作用(请查看Android源中finishAfterTransition()的注释头)。 - Monte Creasor

0
为什么不使用共享同一活动的片段呢?我不认为有必要为这样简单的事情使用两个不同的活动。

好的,使用 Fragment 可以解决这个问题。但是这篇文章更多地讨论了当你需要在活动之间执行共享元素转换,并且第一个活动需要在启动第二个活动后关闭的情况下如何处理。 - Monte Creasor
只要您在完成所需的活动中使用一些常见的东西,该活动就会保持活跃。我认为您应该多想一些创意。最好使用片段,一个片段代替您的启动屏幕,一个片段代替您的第二个活动,并使用第三个片段作为它们之间的动画过渡。希望这个想法能对您有所帮助。 - technik
我认为在SplashActivity中使用Fragment不是一个好的实践。 - Antonis Radz

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