Android 手遊閃屏極簡方案

逃離博客園,搬運一篇2015年作手遊時期的舊文。java

簡約至上 少寫代碼android

爲何須要閃屏

  1. 手機應用程序不該該有閃屏, Google Android 自家的 App 聽說已經全面禁用閃屏。

Splash Screens Are Evil, Don't Use Them!異步

  1. 中國大量手機應用程序,或者說相關從業人員依舊堅持必須存在一個閃屏圖片的審美。

爲何須要原生實現

  1. UnrealEngine3 須要
    UE3 初始化和場景切換時,渲染線程暫停,所以須要使用原生方案顯示圖片或視頻來過渡等待。
  2. cocos2d-x 須要
    cocos2d-x 論壇相關討論帖
  3. Unity3D
    大概相似,未考證。

爲何不該該使用 Splash Activity

「你搜到的都是錯的」
網上搜索 Android 閃屏實現方案,99%的結果都是介紹如何使用一個簡單的 Activity 實現,再過渡切換到真正的 GameActivity 。這種方案僅限教學,實際應用有不少弊端。ide

  1. 這種方案要求在 AndroidManifest.xml 中配置的 LaunchActivity 必須是 SplashActivity
    當須要實現帶參數 Intent 啓動時,SplashActivity 須要正確地傳遞參數(Intent)給 GameActivity。繁瑣。
  2. 遊戲使用 NDK 開發,OpenGL, UI View, thread 須要跟 GameActivity's SurfaceView 綁定。
    SplashActivity 顯示期間,GameActivity 沒法被加載,所以也沒法並行加載遊戲引擎相關實例。致使閃屏事後,GameActivity 仍需一個加載界面用於過渡等待 GameEngine 的啓動耗時。
  3. 遊戲須要接入各類 SDK。不少 SDK 要求在 GameActivity 的生命週期插入諸多 hook 事件代碼。
    例如 onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy() 等等,這些是經常使用 hook 位置。
    SplashActivity 方案使相關邏輯實現更復雜。

一種適合遊戲的簡單閃屏實現方案

  1. 使用一個全屏 Dialog
    Android Dialog 擁有獨立的 Window ,與 GameView 無耦合。
  2. 屏蔽 User Input Event
    Dialog 默認接收全部User Input Event ,不須要傳遞給 GameView,所以與遊戲邏輯無耦合。
  3. 實現動畫
    能夠很方便的使用各類原生 Android Animation ,實現可用的過渡動畫呈現。
  4. 動畫結束後自動消失
    Dialog 能夠自我管理生命週期,再次與遊戲無耦合。
  5. 並行加載遊戲實例
    GameSurfaceView and GameEngine 能夠在 Dialog 顯示期間,後臺並行加載,無耦合,且真正達到異步和節省時間的目標。

代碼示例

  1. 建立全屏 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

閃屏說完了,最後提一下 Loading View

上面說到 UE3 在場景切換時,須要使用平臺原生界面作過渡展現。根據業務需求不一樣,可能有時候不便複用 SplashDialog,那可使用一個獨立 layout View 實現。

相關文章
相關標籤/搜索