逃离博客园,搬运一篇2015年作手游时期的旧文。java
简约至上 少写代码android
“你搜到的都是错的”
网上搜索 Android 闪屏实现方案,99%的结果都是介绍如何使用一个简单的 Activity
实现,再过渡切换到真正的 GameActivity
。这种方案仅限教学,实际应用有不少弊端。ide
AndroidManifest.xml
中配置的 LaunchActivity
必须是 SplashActivity
。Intent
启动时,SplashActivity
须要正确地传递参数(Intent
)给 GameActivity
。繁琐。NDK
开发,OpenGL
, UI View
, thread
须要跟 GameActivity's SurfaceView
绑定。SplashActivity
显示期间,GameActivity
没法被加载,所以也没法并行加载游戏引擎相关实例。致使闪屏事后,GameActivity
仍需一个加载界面用于过渡等待 GameEngine
的启动耗时。GameActivity
的生命周期插入诸多 hook 事件代码。onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()
等等,这些是经常使用 hook
位置。SplashActivity
方案使相关逻辑实现更复杂。Dialog
Android Dialog
拥有独立的 Window
,与 GameView
无耦合。User Input Event
Dialog
默认接收全部User Input Event
,不须要传递给 GameView
,所以与游戏逻辑无耦合。Android Animation
,实现可用的过渡动画呈现。Dialog
能够自我管理生命周期,再次与游戏无耦合。GameSurfaceView and GameEngine
能够在 Dialog
显示期间,后台并行加载,无耦合,且真正达到异步和节省时间的目标。public class NSSplashDialog extends Dialog {
private PercentFrameLayout mLayout = null;
private ImageView mImageView = null;
public NSSplashDialog(Context context) {
super(context, android.R.style.Theme_NoTitleBar_Fullscreen);
setContentView(R.layout.splash);
mLayout = (PercentFrameLayout)findViewById(R.id.layout_splash);
mImageView = (ImageView)this.findViewById(R.id.iv_splash);
}
}
复制代码
2 . 屏蔽 User Input Event
动画
setCanceledOnTouchOutside(false);
setCancelable(false);
复制代码
3 . 实现动画this
private AlphaAnimation mAnimation = null;
private int mBitmapIndex = 0;
mAnimation = new AlphaAnimation(0.0f, 1.0f); //fade in, fade out
mAnimation.setDuration(2000);//2 seconds
mAnimation.setRepeatCount(3); //show 4 images
mAnimation.setAnimationListener(new Animation.AnimationListener(){
@Override
public void onAnimationStart(Animation animation) {
mBitmapIndex = 0;
mLayout.setBackgroundColor(Color.WHITE);
mImageView.setImageDrawable(BitmapUtil.loadDrawable(getContext(), R.drawable.splash0));
}
@Override
public void onAnimationEnd(Animation animation) {
mBitmapIndex = 0;
kick(false);
}
@Override
public void onAnimationRepeat(Animation animation) {
mBitmapIndex++;
switch(mBitmapIndex) {
case 1:
mLayout.setBackgroundColor(Color.WHITE);
mImageView.setImageDrawable(BitmapUtil.loadDrawable(getContext(), R.drawable.splash1));
break;
case 2:
mLayout.setBackgroundColor(Color.BLACK);
mImageView.setImageDrawable(BitmapUtil.loadDrawable(getContext(), R.drawable.splash2));
break;
case 3:
mLayout.setBackgroundColor(Color.BLACK);
mImageView.setImageDrawable(BitmapUtil.loadDrawable(getContext(), R.drawable.splash3));
break;
default:
break;
}
}
});
mImageView.setAnimation(mAnimation);
复制代码
4 . 动画结束后自动消失spa
在onAnimationEnd()
中调用kick(false)
,即关闭本身。线程
实测发现部分系统有bug:onAnimationEnd() 和 cancel() 可能会死循环,所以添加保护逻辑判断 hasEnded()code
public void kick(boolean show) {
if(show) {
show();
mAnimation.start();
} else {
if(!mAnimation.hasEnded()) {
mAnimation.cancel();
}
dismiss();
}
}
复制代码
5 . 闪屏与游戏并行加载视频
GameActivity
生命周期中, 在 onCreate()
建立 SplashDialog
实例,在 onDestroy()
清除 SplashDialog
实例。
//Create
mSplashDialog = new NSSplashDialog(this);
mSplashDialog.kick(true);
//Destroy
if(mSplashDialog != null && mSplashDialog.isShowing()) {
mSplashDialog.kick(false);
}
复制代码
闪屏说完了,最后提一下 Loading View
。
上面说到 UE3 在场景切换时,须要使用平台原生界面作过渡展现。根据业务需求不一样,可能有时候不便复用 SplashDialog
,那可使用一个独立 layout View
实现。