在显示主要 Activity 之前,我的应用程序显示启动屏幕1秒钟。初始屏幕和主要 Activity 都共享一个公共(public)图像,该图像需要从初始屏幕的中心到主要 Activity 布局的顶部进行动画处理。

如果在初始 Activity 中将初始屏幕实现为<layer-list>背景图像(请参阅Splash Screens the Right WayHow do I make a splash screen?)时,如何完成此动画并不明显,我决定将初始屏幕实现为正常 Activity 并使用共享元素过渡以动画化两个 Activity 之间的图像。最初,我在闪屏 Activity 中使用了以下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);
    }
}

这种方法有两个问题:
  • 在调用finish()后立即调用startActivity()会导致启动动画窗口在动画开始之前被隐藏/破坏,从而导致主屏幕在动画过程中暂时闪烁。
  • 从主 Activity 中按回去会自动触发共享元素返回转换,这导致图像在主 Activity 窗口关闭后在主屏幕上悬浮500毫秒。返回转换失败,因为启动 Activity 已经调用了finish(),因此不再位于后堆栈上。

  • 为了解决第一个问题,我将finish()调用包装在postDelay()Runnable中,以确保仅在共享元素转换完成后才调用它。在我的应用程序中,可以使用1500毫秒的延迟,但是应该根据其他用例所需的时间来调整该值。
    ...
    
    imageView.postDelayed(() -> {
        ActivityCompat.startActivity(SplashActivity.this, intent, options.toBundle());
        imageView.postDelayed(this::finish, 1500);
    }, 1000);
    

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

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

    最佳答案

    为什么不使用共享相同 Activity 的片段呢?我看不出有这么简单的事情使用2种不同 Activity 的理由。

    07-24 09:47
    查看更多