Android 手游闪屏极简方案

逃离博客园,搬运一篇2015年做手游时期的旧文。

简约至上 少写代码

为什么需要闪屏

  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 。这种方案仅限教学,实际应用有很多弊端。

  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 . 实现动画

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 . 动画结束后自动消失

onAnimationEnd()中调用kick(false),即关闭自己。

实测发现部分系统有bug:onAnimationEnd() 和 cancel() 可能会死循环,因此添加保护逻辑判断 hasEnded()

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 实现。

转载于:https://juejin.im/post/5cee10de51882512c54cad17

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值