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

Android Studio精彩案例(六)《使用一个Demo涵盖补间动画所有知识》

2017-01-02 21:14 603 查看
转载本专栏文章,请注明出处,尊重原创 。文章博客地址:道龙的博客

元旦假期里,闲的无事,看到美团加载数据的动画,就突想写个Demo把动画知识集成一下。后来想了想,还是直接用一个Demo来把所有动画知识穿插起来算了,该Demo涉及大多数动画应用场景。本篇案例,使用补间动画完成一个简单的动画功能集,会涉及多种形式的动画实现(即使补间动画很老套,但一些简单的动画功能还是可以选择它的)。其实在实际开发中也能看到这些影子。例如很多应用刚打开时候会有一些简单的动画效果,有的应用切换Activity的时候,也带有简单的平移动画效果更美观点,有的应用输入用户名密码错误会有抖动效果等等。同时会自定义View方式自定义一个进度条,模拟美团加载;模拟wifi链接网络;由于几个Activity功能差不多,我对其做一个简单的封装,抽取了BaseActivity。本案例,就是基于这些动画特性做的简化而形成的一个大Demo[界面丑陋,勿喷]。
GitHub下载源代码,打开代码传送门----------------->>>https://github.com/codeydl/App01

本文参考博客:参考博客1:Android 用Animation-list实现逐帧动画 

                         参考博客2:(模拟美团客户端进度提示框) 

先提前浏览一下Demo的效果图:



那么,咱们就从头慢慢来分析这个Demo吧,因为这属于老知识了,网上有很多详细的解析,而且比较简单,又有源代码可以下载,下面只给出核心代码和解析。

一、展示Splash动画

1、动画代码

这里使用旋转、缩放、渐变动画知识,启动Splash动画向导。一般实际项目中,可以在加载动画的时候,进行访问网络数据、拷贝本地数据库等耗时业务,而动画还可以起到对项目介绍的功能。
加载Splash我们可以使用下面代码完成:
//比例动画
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(2000);

//渐变动画
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(2000);

//旋转动画
RotateAnimation rotateAnimation = new RotateAnimation(0,360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);

//动画集合,所有动画一起飞
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);

//启动动画
mRl_splash_view.startAnimation(animationSet);使用动画集AnimationSet加载前述三种动画,然后使用一个View对象启动这个动画,把动画集合对象加载进去。

2、自定义的进度条

在播放动画的时候,我们在图片下方加上一个自定义进度条,这就用到自定义进度条的功能,本质上还是使用动画知识。自定义进度条,我们可以按照下面步骤完成:

1)、在res下新建anim文件,创建my_progress.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/progess">
<!--自定义进度条,依托旋转动画。只需要引入一张图片即可。然后在需要使用该进度条的地方
ProgressBar位置下面。引入进度条:方式、android:indeterminateDrawable="@anim/my_progress"引入默认进度条
android:indeterminateDuration="800"修改旋转一圈耗费的时间-->
</rotate>上边我们@drawable/给出一张图片就行了
然后在需要使用这个自定义进度条的地方引入就好了,引入方式上边已经注释。

2)、引入自定义进度条

<ProgressBar
android:indeterminateDrawable="@anim/my_progress"
android:indeterminateDuration="800"

3、界面切换

界面切换使用Handler延时两秒后,完成进入主界面操作
Handler发消息方

//两秒后发消息进入设置界面
mHandler.sendEmptyMessageDelayed(1,2000);然后Handler接收消息方代码:
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
//进入Step1Activity
Intent intent = new Intent(SplashActivity.this,Step1Activity.class);
startActivity(intent);
finish();
break;

default:
break;
}
}
};

二、进入几个设置界面

由于几个设置界面只是为了展示切换Activity时平移的效果,几个功能大同小异。我把活动抽取了一下,在每个活动里面只需要简单的几行代码,就能完成效果。

1、先完成活动可切换

我们从第二个活动入手,说明为何要抽取基类。

第二个活动布局代码就两个按钮:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_step2_activiity"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<Button
android:onClick="next"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="下一步"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<Button
android:onClick="pre"
android:layout_alignParentBottom="true"
android:text="上一步"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</RelativeLayout>
那么其他的活动与之类似,我们给Button设置了可点击事件。那么在每一个活动里面都会有同样的效果,即点击下一步动画切换下一个活动;点击上一步动画切换下一个活动。按钮事件通过next(View v){}方式实现,那么所有活动肯定有多余代码量,因此向上抽取同样功能,代码如下:
public void next(View v){
//启动下一个活动
nextActivity();
}以及:
public void pre(View v){
preActivity();
}以进入一下个活动为分析点:
我们发现调用了nextActivity();这个是一个抽象方法,让子类实现,点击下一步按钮,实际调用具体子类的该方法。因为,抽取了基类,还要实现下一步切换没有什么其他好的方式去实现。那么这个方法具体子类如何实现呢?
我们往往可能会直接重写该方法:
@Override
protected void nextActivity() {
Intent intent = new Intent(this,Setup3Activity,class);
startActivity(intent);
finish();
}那么我们又要想了,所有启动下一个活动都要重复写代码,反过来启动上一个活动也要写类似的Intent....这样的代码,因而切换活动可以写在基类里面。怎么实现呢?
在基类里面定义一个方法就好了,它的功能用于专门启动任意一个活动:
public void startActivity(Class activity){
Intent intent = new Intent(this,activity);
startActivity(intent);
finish();
}子类如果想启动某一个活动,只需要重写上边的方法,并且传入要启动的活动.class就好了。比如我活动二中想启动Setup3Activity,以及启动Setup1Activity:
@Override
protected void nextActivity() {
startActivity(Step3Activity.class);
}

@Override
protected void preActivity() {
startActivity(Step1Activity.class);
}是不是节省好多代码?哈哈,那是肯定的。完成了活动切换,然后考虑活动切换的动画切换

2、Activity动画切换效果写前分析:

1)、分析

最好的解释,莫过于图片。我用一张图片分析了切换的原理:



经过上图的分析,就可以给出切换下一个活动和切换上一个活动的动画xml了。以点击下一步时候需要的动画为出发点:

2)代码:

next_in.xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="100%"
android:toXDelta="0"
android:duration="300"
>

</translate>next_out.xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:fromYDelta="0"
android:duration="300"
android:toXDelta="-100%"
android:toYDelta="0">

</translate>

3)、基类里面加入活动切换的代码:

使用APIoverridePendingTransition();

由于动画切换也是每个活动所具备的,因此还可以写在基类里面:
public void nextAnimation(){
//加入动画方式启动下一个活动
overridePendingTransition(R.anim.next_in,R.anim.next_out);
}

public void preAnimation(){
//加入动画方式启动上一个活动
overridePendingTransition(R.anim.pre_in,R.anim.pre_out);
}

只需要在基类点击方法next(View v){}和pre(View v){}里面调用一下就好了。
public void next(View v){
................
//使用动画
nextAnimation();
}以及:
public void pre(View v){
..............
preAnimation();
}

以及在Setup3Activity进入主界面时候的动画(点击完成按钮,进入主界面):
public void complete(View v){
startActivity(MainActivity.class);
overridePendingTransition(R.anim.bottom_in,R.anim.top_out);
}

三、主活动界面布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_weight="1"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/et_activity_main_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入内容"/>

<Button
android:id="@+id/btn_activity_main_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录"/>
</LinearLayout>

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp">

<ImageView
android:layout_centerHorizontal="true"
android:id="@+id/animationIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5px"
android:src="@drawable/animation1"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">

<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="5px"
android:text="顺序显示"/>

<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="5px"
android:text="停止"/>

<Button
android:id="@+id/buttonC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="5px"
android:text="倒序显示"/>
</LinearLayout>

</RelativeLayout>
</LinearLayout>


这里第EditText与紧跟的button是一组。点击登录按钮,如果EditText无内容,就实现EditText抖动效果。如果有内容点击就弹出自定义对话框,实现模拟美团加载数据功能。最底下是一组,模拟wifi链接动画效果。
那么就一点点来实现出来吧:

1、监听EditText是否空,为空实现抖动效果:

抖动效果本质上其实就是平移动画,加入一个周期即可。
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromXDelta="0"
android:interpolator="@anim/cycle_8"
android:toXDelta="10" />
<!--平移10dp长度;interpolator动画插入器:表示动画循环多少次-->平移10个单位,500毫秒完成一个周期。引入一个周期:
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:cycles="8" />
<!--动画插入器-->在代码中点击button,抖动效果代码如下:
//抖动效果
Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.shake);
etactivitymaincontent.startAnimation(animation);//给edittext加入动画

2、最底部完成wifi链接动画:

此时也是动画效果,使用多张动画,完成隔一段时间切换不同图片,达到动态效果。
方式如下:
在drawable下面,新建animation1(用于顺序动画)和animation2.(用于逆序动画)
只针对animation1做分析:
<?xml version="1.0" encoding="utf-8"?>
<!--
根标签为animation-list,其中oneshot代表着是否只展示一遍,设置为false会不停的循环播放动画
根标签下,通过item标签对动画中的每一个图片进行声明
android:duration 表示展示所用的该图片的时间长度
-->
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true"
>
<item android:drawable="@drawable/icon1" android:duration="150"></item>
<item android:drawable="@drawable/icon2" android:duration="150"></item>
<item android:drawable="@drawable/icon3" android:duration="150"></item>
<item android:drawable="@drawable/icon4" android:duration="150"></item>
<item android:drawable="@drawable/icon5" android:duration="150"></item>
<item android:drawable="@drawable/icon6" android:duration="150"></item>
</animation-list>加入多张图片,并制定了动画展示时间。oneshot=true表示动画只播放一次。如果制定为fasle则不停的播放了。
那马在代码中,我们可以同过下面方式加入动画:
animationIV.setImageResource(R.drawable.animation1);
mAnimationDrawable = (AnimationDrawable) animationIV.getDrawable();
mAnimationDrawable.start();把自定义动画xml作为参数设置到setImageResource中设置一个资源,再调用getDrawable方法返回值Drawable,注意这里强转为AnimationDrawable,只有这个对象才可以启动这种方式的动画。
当点击停止的时候:
mAnimationDrawable.stop();animation2原理一模一样。

3、模拟美团登录加载数据

1)、布局:

<ImageView
android:id="@+id/iv_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/frame_meituan"/>主要说明一下imageview。他通过android:background="@drawable/frame_meituan"引入一个动画xml文件。这个文件原理跟上边的模拟wifi效果又是一样的了。动画效果也是两张图片不停地切换。

2)、自定义对话

模拟美团登录效果,其实也是两张动画的不停切换。原理和上边一样。只不过这里加入了自定义对话框功能:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initData();
}

private void initData() {
// 通过ImageView对象拿到背景显示的AnimationDrawable
mAnimation = (AnimationDrawable) mIvLoading.getBackground();

//主界面点击登录,立即调用这里的动画显示功能
mAnimation.start();

//设置正在加载中信息
mTvLoading.setText(mLoadingTip);
}

private void initView() {
//加载自定义布局,此时MyDialog已经有了该布局的样子
setContentView(R.layout.progress_dialog);// 显示界面
mTvLoading = (TextView) findViewById(R.id.tv_loading);
mIvLoading = (ImageView) findViewById(R.id.iv_loading);
}ProgressDialog不是ViewGroup,自定义布局通过setContentView方法加载进来自定义的布局。要重写onCreate,加入一个自定义布局,并且拿到布局中的实例。当外界初始化Dialog的时候,就会调用onCreate方法。初始化数据我们得到imageview的动画实例,这里同样强制转换为AnimationDrawable,只有这个对象才可以启动这种方式的动画。可见,只要外界一创建自定义对话框对象,就能启动该布局,而且启动动画,调用.show()方法,可以展示该自定义对话框。
当外界调用取消对话框的时候,我们要调用dismiss()方法。因而,我们需要在关闭的时候加入结束动画的代码:
@Override
public void dismiss() {
super.dismiss();
//对话框关闭,同时关闭掉动画。节约资源
mAnimation.stop();
mAnimation = null;
}

构造方法,肯定是传入需要的上下文(这个上下文必须是Activity类型的),需要的设置的文本提示内容,如下:

public MyDialog(Context context,String content) {
super(context);
this.mContext = context;
this.mLoadingTip = content;
}

3)、引用该自定义的对话框。

//模拟美团登录
mDialog = new MyDialog(this, "正在加载中");
mDialog.show();
Handler handler =new Handler();
handler.postDelayed(new Runnable() {

@Override
public void run() {

mDialog.dismiss();
}
}, 3000);//3秒钟后调用dismiss方法隐藏;如果有访问网络,可以设置访问网络成功后的监听,再停止对话框就像使用系统对话框一样,使用这个自定义对话框就好了。我们展示对话框后,并使用handler延时3秒关闭对话框。很简单。
上边实现步骤,我写的很详细,写了好久啊。看完记得加关注点赞啊~
最后,再看看实现的效果吧!



看完的朋友可以关注下,或者微信扫描下方二维码,关注公众号也可以:

打开微信搜索公众号  Android程序员开发指南  或者手机扫描下方二维码 在公众号阅读更多Android文章。
微信公众号图片:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐