逃離博客園,搬運一篇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
實現。