Android 启动页过渡动画效果实现(一)
Android 启动页过渡动画效果实现(二)
一.效果1:缩放、平移、渐变、弹簧弹性动画效果
1.效果图:
2.添加依赖:
//动画
implementation 'com.daimajia.androidanimations:library:1.1.3@aar'
implementation 'io.reactivex:rxandroid:1.2.0'
implementation 'io.reactivex:rxjava:1.1.5'
implementation 'com.jakewharton:butterknife:8.0.1'
3.主函数代码:
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
import com.daimajia.androidanimations.library.Techniques;
import com.daimajia.androidanimations.library.YoYo;
import com.hjq.demo.R;
import com.hjq.demo.ui.activity.sgf.search.SearchviewActivity;
import java.util.concurrent.TimeUnit;
import androidx.appcompat.app.AppCompatActivity;
import butterknife.BindView;
import butterknife.ButterKnife;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
/**
* app启动动画系列
* https://github.com/HMonkey1024/MyLauncher
* https://github.com/darryrzhong/OpenEyes
*/
public final class SgfSplash5Activity extends AppCompatActivity {
@BindView(R.id.logo_outer_iv)
ImageView mLogoOuterIv;
@BindView(R.id.logo_inner_iv)
ImageView mLogoInnerIv;
boolean isShowingRubberEffect = false;
@BindView(R.id.app_name_tv)
TextView mAppNameTv;
private long exitTime;
private TextView tvRegister;
private TextView tvLogin;
private ImageView ivLogo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//全屏
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_sgf_splash5);
ButterKnife.bind(this);
initAnimation();
}
private void initAnimation() {
startLogoInner1();
startLogoOuterAndAppName();
}
private void startLogoInner1() {
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_top_in);
mLogoInnerIv.startAnimation(animation);
}
private void startLogoOuterAndAppName() {
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = animation.getAnimatedFraction();
// KLog.d("fraction: " + fraction);
if (fraction >= 0.8 && !isShowingRubberEffect) {
isShowingRubberEffect = true;
startLogoOuter();
startShowAppName();
finishActivity();
} else if (fraction >= 0.95) {
valueAnimator.cancel();
startLogoInner2();
}
}
});
valueAnimator.start();
}
private void startLogoOuter() {
YoYo.with(Techniques.RubberBand).duration(1000).playOn(mLogoOuterIv);
}
private void startShowAppName() {
YoYo.with(Techniques.FadeIn).duration(1000).playOn(mAppNameTv);
}
private void startLogoInner2() {
YoYo.with(Techniques.Bounce).duration(1000).playOn(mLogoInnerIv);
}
private void finishActivity() {
Observable.timer(1000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1() {
@Override
public void call(Long aLong) {
startActivity(new Intent(SgfSplash5Activity.this, SearchviewActivity.class));
overridePendingTransition(0, android.R.anim.fade_out);
finish();
}
});
}
}
4.布局代码:
5.xml动画:
anim_top_in.xml
fade_out.xml是Android API 28自带的 :
二.效果2:由小到大缩放动画效果
1.效果图:
2.主函数代码:
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.daimajia.androidanimations.library.Techniques;
import com.daimajia.androidanimations.library.YoYo;
import com.hjq.demo.R;
import com.hjq.demo.ui.activity.sgf.search.SearchviewActivity;
import com.hjq.demo.utils.KickBackAnimator;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import androidx.appcompat.app.AppCompatActivity;
import butterknife.BindView;
import butterknife.ButterKnife;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
/**
* app启动动画系列
* https://github.com/HMonkey1024/MyLauncher
* https://github.com/darryrzhong/OpenEyes
*/
public final class SgfSplash6Activity extends AppCompatActivity {
@BindView(R.id.lin)
LinearLayout lin;
@BindView(R.id.tv_sbs)
TextView tv_sbs;
@BindView(R.id.tv_search)
TextView tv_search;
@BindView(R.id.tv_course)
TextView tv_course;
@BindView(R.id.tv_task)
TextView tv_task;
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//全屏
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_sgf_splash6);
ButterKnife.bind(this);
ArrayList textViews = new ArrayList<>();
textViews.add(tv_sbs);
textViews.add(tv_search);
textViews.add(tv_course);
textViews.add(tv_task);
// showAnimation(textViews);
showAnimation();
}
private void showAnimation() {
tv_sbs.setVisibility(View.INVISIBLE);
tv_search.setVisibility(View.INVISIBLE);
tv_course.setVisibility(View.INVISIBLE);
tv_task.setVisibility(View.INVISIBLE);
Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.my_anim_scale2);
tv_sbs.startAnimation(animation);
tv_sbs.setVisibility(View.VISIBLE);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//动画效果
Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.my_anim_scale2);
tv_search.startAnimation(animation);
tv_search.setVisibility(View.VISIBLE);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//动画效果
Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.my_anim_scale2);
tv_course.startAnimation(animation);
tv_course.setVisibility(View.VISIBLE);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//动画效果
Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.my_anim_scale2);
tv_task.startAnimation(animation);
tv_task.setVisibility(View.VISIBLE);
}
}, 500);
}
}, 500);
}
}, 500);
}
private void showAnimation(ArrayList textViews) {
try {
//菜单项弹出动画
for (int i = 0; i < textViews.size(); i++) {
// textViews.get(i).setOnClickListener(this);
textViews.get(i).setVisibility(View.INVISIBLE);
int finalI = i;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
textViews.get(finalI).setVisibility(View.VISIBLE);
//动画效果1
// ValueAnimator fadeAnim = ObjectAnimator.ofFloat(textViews.get(finalI), "translationY", 600, 0);
// fadeAnim.setDuration(2000);
// KickBackAnimator kickAnimator = new KickBackAnimator();
// kickAnimator.setDuration(1500);
// fadeAnim.setEvaluator(kickAnimator);
// fadeAnim.start();
//动画效果2
// Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.anim_top_in);
// textViews.get(finalI).startAnimation(animation);
//动画效果3
// Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.my_anim_scale);
Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.my_anim_scale2);
textViews.get(finalI).startAnimation(animation);
}
}, i * 50 + 1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.布局代码:
4.xml动画
a.my_anim_scale2.xml
b.my_anim_scale.xml
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//全屏
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_sgf_splash6);
ButterKnife.bind(this);
ArrayList textViews = new ArrayList<>();
textViews.add(tv_sbs);
textViews.add(tv_search);
textViews.add(tv_course);
textViews.add(tv_task);
// showAnimation(textViews);
tv_sbs.setVisibility(View.INVISIBLE);
tv_search.setVisibility(View.INVISIBLE);
tv_course.setVisibility(View.INVISIBLE);
tv_task.setVisibility(View.INVISIBLE);
Animation animation = AnimationUtils.loadAnimation(SgfSplash6Activity.this, R.anim.my_anim_translate2);
iv_icon.startAnimation(animation);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
showAnimation();//动画结束时执行
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
my_anim_translate2.xml 从上到下掉落弹性动画效果
my_anim_translate3.xml 旋转渐变缩放一起执行动画效果
5.看看依赖:
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileVersion
// 使用 JDK 1.8
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
abortOnError false
}
defaultConfig {
// 无痛修改包名:https://www.jianshu.com/p/17327e191d2e
applicationId "com.hjq.demo"
minSdkVersion 19
targetSdkVersion rootProject.ext.targetVersion
versionCode 10
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// 仅保留中文语种的资源
resConfig 'zh'
// 仅保留 xxhdpi 图片资源(目前主流分辨率 1920 * 1080)
resConfig 'xxhdpi'
// 仅保留两种架构的 so 库
ndk {
// armeabi:已经淘汰(0%)
// armeabi-v7a:曾经主流的架构平台(20%)
// arm64-v8a:目前主流架构平台(80%)
//"x86_64",
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "armeabi"
}
// 开启 Dex 分包
multiDexEnabled true
// 混淆配置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-app.pro'
javaCompileOptions {
annotationProcessorOptions {
// EventBus Apt 索引类生成位置
arguments = [ eventBusIndex : applicationId + '.MyEventBusIndex' ]
}
}
}
// APK 签名的那些事:https://www.jianshu.com/p/a1f8e5896aa2
signingConfigs {
debug {
storeFile file(StoreFile)
storePassword StorePassword
keyAlias KeyAlias
keyPassword KeyPassword
}
release {
storeFile file(StoreFile)
storePassword StorePassword
keyAlias KeyAlias
keyPassword KeyPassword
}
}
buildTypes {
release {
// 移除无用的资源文件
shrinkResources true
// ZipAlign 优化
zipAlignEnabled true
// 设置混淆
minifyEnabled true
// 正式环境签名
signingConfig signingConfigs.release
// 正式环境下的 BuglyId
buildConfigField "String", "BUGLY_ID", "\"请自行替换 Bugly 上面的 AppID\""
}
debug {
// 移除无用的资源文件
shrinkResources false
// ZipAlign 优化
zipAlignEnabled false
// 设置混淆
minifyEnabled false
// 开发环境签名
signingConfig signingConfigs.debug
// 开发环境下的 BuglyId
buildConfigField "String", "BUGLY_ID", "\"请自行替换 Bugly 上面的 AppID\""
}
}
// 默认渠道名
flavorDimensions "default"
// 友盟多渠道打包
productFlavors {
tencent {} // 应用宝
baidu {} // 百度
xiaomi {} // 小米
huawei {} // 华为
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
// JNI 目录
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
// 执行配置
applicationVariants.all { variant ->
// Apk 输出配置
variant.outputs.all { output ->
def appName = "AndroidProject"
if (variant.buildType.name == 'debug') {
outputFileName = appName + '_v' + versionName + '_' + variant.buildType.name + '.apk'
} else {
outputFileName = appName + '_v' + versionName + '_' + new Date().format("yyyyMMdd") + '_' + variant.productFlavors[0].name + '_' + variant.buildType.name + '.apk'
}
}
// AndroidManifest 输出配置
variant.outputs[0].processManifest.doLast {
def manifestFile = "${manifestOutputDirectory}/AndroidManifest.xml"
def updatedContent = new File(manifestFile).getText('UTF-8')
.replaceAll("UMENG_APPKEY_VALUE", "5cb16d93570df399fd0014e2") // 友盟 AppKey
.replaceAll("QQ_APPID_VALUE", "100424468") // QQ AppId
.replaceAll("QQ_APPKEY_VALUE", "c7394704798a158208a74ab60104f0ba") // QQ Key
.replaceAll("WX_APPID_VALUE", "wxdc1e388c3822c80b") // 微信 AppId
.replaceAll("WX_APPKEY_VALUE", "3baf1193c85774b3fd9d18447d76cab0") // 微信 Key
new File(manifestFile).write(updatedContent, 'UTF-8')
}
}
}
// api 与 implementation 的区别:https://www.jianshu.com/p/8962d6ba936e
dependencies {
// 依赖 libs 目录下所有 jar 包
implementation fileTree(include: ['*.jar'], dir: 'libs')
// 依赖 libs 目录下所有 aar 包
implementation fileTree(include: ['*.aar'], dir: 'libs')
// 基础库(不包任何第三方框架)
implementation project(':base')
// 自定义 View
implementation project(':widget')
// Glide 隔离
implementation project(':image')
// 友盟隔离
implementation project(':umeng')
// 谷歌 Support 包
implementation "androidx.appcompat:appcompat:$rootProject.ext.appcompatVersion"
implementation "com.google.android.material:material:$rootProject.ext.materialVersion"
// Dex 分包,解决 64k 方法问题
implementation 'androidx.multidex:multidex:2.0.1'
// ButterKnife 注解库:https://github.com/JakeWharton/butterknife
implementation 'com.jakewharton:butterknife:10.1.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
// EventBus 事件总线:https://github.com/greenrobot/EventBus
implementation "org.greenrobot:eventbus:3.1.1"
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
// 状态栏沉浸:https://github.com/gyf-dev/ImmersionBar
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
// 权限请求框架:https://github.com/getActivity/XXPermissions
implementation 'com.hjq:xxpermissions:6.0'
// 标题栏:https://github.com/getActivity/TitleBar
implementation 'com.hjq:titlebar:6.0'
// 吐司工具类:https://github.com/getActivity/ToastUtils
implementation 'com.hjq:toast:8.0'
// 支持放大缩放的 ImageView:https://github.com/chrisbanes/PhotoView
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
// ViewPager 指示器:https://github.com/romandanylyk/PageIndicatorView
implementation 'com.romandanylyk:pageindicatorview:1.0.3'
// Bugly 异常捕捉:https://bugly.qq.com/docs/user-guide/instruction-manual-android/?v=20190418140644
implementation 'com.tencent.bugly:crashreport:3.0.1'
implementation 'com.tencent.bugly:nativecrashreport:3.7.1'
// 本地异常捕捉框架:https://github.com/Ereza/CustomActivityOnCrash
implementation 'cat.ereza:customactivityoncrash:2.2.0'
// 内存泄漏捕捉:https://github.com/square/leakcanary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
// 网络请求(待发布):https://github.com/getActivity/EasyHttp
// 国际化:https://github.com/getActivity/MultiLanguages
// 悬浮窗:https://github.com/getActivity/XToast
// 上拉刷新下拉加载:https://github.com/scwang90/SmartRefreshLayout
// 工具类:https://github.com/Blankj/AndroidUtilCode
// 轮播图:https://github.com/bingoogolapple/BGABanner-Android
// 二维码:https://github.com/bingoogolapple/BGAQRCode-Android
// 第三方支付:https://github.com/getActivity/RxPay
// Log 打印:https://github.com/elvishew/XLog
// 图片压缩:https://github.com/Curzibn/Luban
// 对象存储:https://github.com/leavesC/DoKV
// 数据注入:https://github.com/JumeiRdGroup/Parceler
implementation 'com.android.support:design:26.1.0'
//约束布局
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
//第三方适配器
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
implementation 'com.google.code.gson:gson:2.8.0'
// implementation 'com.github.bumptech.glide:glide:3.7.0'
//通用标题栏
implementation 'com.hjq:titlebar:6.0'
implementation 'com.makeramen:roundedimageview:2.3.0'
//高度自定义的开源安卓视频框架
implementation 'cn.jzvd:jiaozivideoplayer:7.0.5'
implementation 'com.danikula:videocache:2.7.0'
// implementation 'com.github.bumptech.glide:glide:4.7.1'
implementation 'com.github.bumptech.glide:glide:4.9.0'
//
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
dependencies {
implementation ('com.google.android.exoplayer:exoplayer:2.9.1'){
}
}
// dependencies {
// implementation ('com.github.bumptech.glide:glide:4.7.1'){
//
// }
// }
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
// implementation 'com.google.android.exoplayer:exoplayer:2.9.1'
//圆形图片
implementation 'de.hdodenhof:circleimageview:2.2.0'
//弹簧动画效果
implementation 'com.facebook.rebound:rebound:0.3.8'
//抖音APP点赞效果实现,模仿抖音APP双击屏幕蹦出心图,特点: 1. 可以自定义图片 2. 可以自定义旋转角度 3. 超级简洁,占用内存小
implementation 'com.github.KevinYou128:HotHeart:v1.2'
//轮播图 https://github.com/bingoogolapple/BGABanner-Android
implementation 'com.android.support:support-v4:latestVersion'
implementation 'cn.bingoogolapple:bga-banner:2.2.7@aar'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'cn.bingoogolapple:bga-baseadapter:1.2.9@aar'
implementation 'com.facebook.fresco:fresco:1.5.0'
// implementation 'com.android.support:multidex:1.+'
//轮播图 https://github.com/bingoogolapple/BGABanner-Android
//一个富有动感的Sheet(选择器)
implementation 'com.github.zzz40500:AndroidSweetSheet:1.1.0'
//实现九宫格框架
// implementation 'com.wobiancao:imagenice9lib:1.0.1'
// implementation('com.wobiancao:imagenice9lib:1.0.1') {
// transitive = true;
// }
//阿里巴巴推出的一个RecyclerView得扩展库vlayout
implementation ('com.alibaba.android:vlayout:1.2.8@aar') {
transitive = true
}
//3D 外科调试工具,可发现您应用下的图层
implementation 'com.jakewharton.scalpel:scalpel:1.1.2'
//RecyclerView扩展库提供了高级功能。 (例如,Google的Inbox应用(例如滑动,Play Music应用(例如,拖放排序)
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
//
implementation 'com.alibaba:fastjson:1.2.56'
implementation 'com.flyco.tablayout:FlycoTabLayout_Lib:2.0.0@aar'
implementation 'com.trello:rxlifecycle-components:0.6.1'
implementation 'com.zhy:flowlayout-lib:1.0.1'
//动画
implementation 'com.daimajia.androidanimations:library:1.1.3@aar'
}
Android 启动页过渡动画效果实现(一)
Android 启动页过渡动画效果实现(二)