您的位置:首页 > 移动开发 > Unity3D

自定义Unity闪屏ForAndroid

2017-10-16 21:27 239 查看
嗯,工作中遇到策划提了一个小需求:酷炫的闪屏。。

我们知道unity自带的闪屏。。。真·一张图片,其实没有任何的动画效果,所以来看一下怎么定义自己的闪屏方案吧。

基本思路就是用Android的闪屏内嵌到Unity中,通过jar包和Android资源以及程序启动Activity设置,实现自定义的闪屏。

首先使用Eclipse或Android Studio新建一个Library工程,新建闪屏Activity及布局文件,布局文件很简单,一张match_parent的图片就可以了,闪屏代码包含两个动画,缩放和透明度变化,可以自己定制别的效果,比如旋转动画什么的。

源码:

public class Splash extends Activity {

final String TAG = "Splash";
private final int maxSupport = 5;
AnimationListenerBack animationListener;
//  AlphaAnimation alphaAni;
ImageView splashView;
Class<?> next;
private boolean ispause;
private long splashDur = 3000;
private float fromAlpha = 0.1f;
private float toAlpha = 1.0f;
private float fromScale = 1.0f;
private float toScale = 1.2f;
private int splashCount = 1;
private int currentIndex = 1;
private WeakReference<Drawable> splash;//弱引用防止OOM

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setondraweble();
setContentView(R.layout.activity_splash1);
splashView = this.findViewById(R.id.splash);
getSplashCount();
initView();
}

private void getSplashCount() {
// TODO Auto-generated method stub
String count = getString(R.string.splash_count);
splashCount = Integer.parseInt(count);
if(splashCount > maxSupport)
splashCount = maxSupport;
nextLoader(getString(R.string.main_activity));
}

private void nextLoader(String className) {
ClassLoader loader = this.getClassLoader();
try {
;
Log.i(TAG, "loadClass: ===> " + className);
next = loader.loadClass(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.e("Splash", String.format("not find main entry, please check strings setting main_activity"));
}
}

private void initView() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
splash = new WeakReference<Drawable>(getResources().getDrawable(getSplashId(currentIndex)));
} else {
splash = new WeakReference<Drawable>(getResources().getDrawable(getSplashId(currentIndex)));
}
splashView.setImageDrawable(splash.get());
initAnimation();
}

private int getSplashId(int curIndex) {
int id = R.mipmap.sp1;
switch (curIndex) {

case 1:
id = R.mipmap.sp1;
break;
case 2:
id = R.mipmap.sp2;
break;
case 3:
id = R.mipmap.sp3;
break;
case 4:
id = R.mipmap.sp4;
break;
case 5:
id = R.mipmap.sp5;
break;
default:
break;

}
return id;
}

private void initAnimation() {
AnimationSet aniSet = new AnimationSet(true);
WindowManager wm = getWindowManager();
int centerX = wm.getDefaultDisplay().getWidth() / 2;
int centerY = wm.getDefaultDisplay().getHeight() / 2;
Log.i("center", String.format("## centerX:%d, centerY:%d", centerX, centerY));
WeakReference<ScaleAnimation> scaleAnimation = new WeakReference<>(new ScaleAnimation(fromScale, toScale, fromScale, toScale, centerX, centerY));
WeakReference<AlphaAnimation> alphaAnimation = new WeakReference<>(new AlphaAnimation(this.fromAlpha, this.toAlpha));
aniSet.setDuration(splashDur);
aniSet.setFillAfter(true);
aniSet.addAnimation(scaleAnimation.get());
aniSet.addAnimation(alphaAnimation.get());
animationListener = new AnimationListenerBack();
aniSet.setAnimationListener(animationListener);
splashView.startAni
4000
mation(aniSet);
}

private void endAnimation(){
WeakReference<AlphaAnimation> end = new WeakReference<>(new AlphaAnimation(toAlpha, 0.01f));
end.get().setFillAfter(true);
end.get().setDuration(1000);
end.get().setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
currentIndex++;
initView();
}

@Override
public void onAnimationRepeat(Animation animation) {

}
});
splashView.startAnimation(end.get());
}

private void setondraweble() {
requestWindowFeature(Window.FEATURE_NO_TITLE);
int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
Window window = this.getWindow();
window.setFlags(flag, flag);
}

@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
ispause = true;
}

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
ispause = false;
}

private class AnimationListenerBack implements AnimationListener {

@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub

if(currentIndex < splashCount){
endAnimation();
}else{
Intent intent = new Intent();
if (next == null) {
try {
throw new Exception("not find main entry!");
} catch (Exception e) {
e.printStackTrace();
return;
}
}
intent.setClass(Splash.this, next);
startActivity(intent);
finish();
}
}

@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub

}
}


用到的知识点:

安卓动画Animation

Java 弱引用WeakReference

Java 反射

适用平台:Andorid

支持工具:

1. Eclipse

2. Android Studio

3. Unity

最大支持闪屏数量:5

关于使用:

在Eclipse中使用:

引用Libarbry工程:SplashUtilsLibrary



设置启动Activity:

将manifest xml文件中的启动入口注释,如图,或者设置为Library工程的Splash为主Activity.



在Android Studio中使用:

导入Module SplashUtilsLibrary:

File>New>Import New Moudle ,选择SplashUtilsLibrary工程即可



并在gradle里进行引用:



设置启动Activity,设置方式和Eclipse中一致.

在Unity中使用:

导入资源:

Res目录: 对应unity目录:plugins/Android/res

闪屏图片资源

将自定义的闪屏图片导入到Unity对应目录中:以sp格式命名

layout:

导入布局文件activity_splash1.xml到unity对应目录

在string.xml中添加以下配置:

<string name="main_activity">dy.cn.splashdemo.MainActivity</string>
<string name="splash_count">3</string>


修改splash_count的值即可修改闪屏数量,最大支持5张.

在AndroidManifest中添加配置:

<activity
android:name="cn.dy.jzcj.Splash"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name="com.unity3d.player.UnityPlayerActivity"
android:screenOrientation="landscape">
<meta-data
android:name="unityplayer.UnityActivity"
android:value="true" />
</activity>


其中cn.dy.jzcj是包名,此包名需与工程 Bundle Identifier ,以及下面说到的jar包包名保持一致。



导入jar包:

在Eclipse中修改包名:



然后build project

拷贝bin目录下生成的jar包到unity 中plugins/Android/libs中

包名须与Unity工程包名保持一致。

自定义闪屏数量:

修改strings.xml中splash_count,并添加对应闪屏资源即可

更换闪屏资源:

Unity、Eclipse中更新drawable下对应图片资源即可,注意命名格式。

Android Studio中更新mipmap下对应图片资源即可。

自定义跳转Activity入口:

Android Studio、Eclipse中修改strings.xml中main_activity值为闪屏结束需要跳转的Activity,格式为:

包名+Activity名称

Unity中若由自定义闪屏直接跳到Unity程序,则main_activity固定为:com.unity3d.player.UnityPlayerActivity。

若自定义闪屏结束后需跳转到其他Activity,则设置和Eclipse、Android Studio中一致即可。

最后分享一些知识点吧:

可能有人会好奇了,为什么jar包包名,AndroidManifest中配置包名必须和Unity工程Bundle Identifier保持一致呢?

嗯,之前我尝试过jar包不修改包名,也就是和Unity Bundle Identifier无关的一些尝试,但是只有在一种情况下才会成功,那就是Unity中生成的资源Id和Android中资源Id完全一致的情况下,换种说法就是Unity中Plugins/Android/res目录和Android导出jar包完全一致。

总的来说,这其实是Android资源管理机制导致的必然结果,我们知道Android会为所有使用到的资源生成一个对应的资源Id,Eclipse中是./gen/R.java,AS中是./build/intermediates/class/debug/包名/R.class,如图:



我们可以看到资源id从0x7f020000开始,按照drawable 、id、layout、string、style的顺序向下生成。而Unity打包时,plugins/Android/res下或者ids,只要出现一个不对应,或多或少的资源,打包时重新生成的资源Id就和Eclipse中生成的不对应了。

为什么要说这个呢,Android打包后会为每个包名生成对应的目录,包含对应的资源及资源Id等,比如我们使用不一样的包名,下图为使用apktools解包后的包结构:



可以看到不同包名映射生成的资源Id目录也不同,而我们使用的是Unity中的资源,所以应该保持jar包包名和Unity Bundle Identifier一致,这样在jar包和Unity就会处于同一目录下,jar代码中映射资源就可以正确获取到了。

这无疑是个比较蛋疼的地方,不修改包名还好,如果Unity中修改了包名,那我们就需要修改Eclipse工程包名重新导出jar包来用了,我也尝试过导出jar包时将R.java一起导出,但是还是前面说的,资源不对应会导致Id不一致,行不通,目前还是没有想到有什么好的解决方案,如果小伙伴们谁有更好的办法,请记得告诉我,感激不尽。。

end of:源码下载

http://pan.baidu.com/s/1dEX7NZr

密码:qpmn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息