Android共享元素从初始屏幕转换为主要活动

时间:2017-04-27 20:12:31

标签: android android-animation splash-screen android-transitions shared-element-transition

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

如果在主要活动中将启动画面实现为<layer-list>背景图片(参见Splash Screens the Right WayHow do I make a splash screen?),如何完成此动画并不明显,我决定将初始屏幕实现为普通活动,并使用共享元素转换来为两个活动之间的图像设置动画。最初,我在启动活动中使用了以下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. 在调用finish()后立即调用startActivity()会导致在动画启动之前隐藏/销毁启动活动窗口,这会导致主屏幕在动画期间暂时闪烁进入视图。
  2. 从主活动返回会自动触发共享元素返回转换,导致主活动窗口关闭后图像在主屏幕上显示为500毫秒。返回转换失败,因为splash活动已经调用了finish(),因此不再位于后栈。
  3. 为了解决第一个问题,我将finish()调用包装在postDelay()Runnable中,以确保只有在共享元素转换完成后才会调用它。在我的应用程序中有1500毫秒的延迟,但应根据其他用例所需的时间调整该值。

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

    要解决第二个问题,我会覆盖主要活动的onBackPressed()方法,直接调用finish(),从而避免默认实施对finishAfterTransitions()的调用。这可以防止Activity尝试执行共享元素返回转换。

    @Override
    public void onBackPressed() {
        finish();
    }
    

    任何可以改进此解决方案的替代方法或建议都将受到赞赏。

3 个答案:

答案 0 :(得分:0)

为什么不使用共享相同活动的片段?我没有理由为这么简单的事情使用2种不同的活动。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我也遇到了类似的问题。

一种方法可以是不在启动画面中调用finish(),而在下一屏幕中finishAffinity()上调用onBackPressed()