为了描述方便,下文中我们把执行动画的组件暂时称为“目标组件”;
1.1 概述
- 动画的意义: 视觉效果(良好观感)、 引导用户(理解我们的应用功能);
- 下文将笔记: 逐帧动画、 视图动画、 属性动画
- 逐帧动画:逐帧动画的基础是帧,也即图片,图片一般由美工制作; 没有原图就无法制作逐帧动画,则应用范围比较小;
- 视图动画:应用广泛;
操作的是
视图对象
,可以令视图对象产生透明度渐变、位移、旋转等效果
; 但是也有它的局限性(局限于视图)
; - 属性动画:操作的对象
不再局限于视图
,可以真实地改变
对象的属性
;
2 逐帧动画
- 概述: 逐帧动画也称图片动画, 通过在一个固定区域, 逐张地呈现一系列事先加载好的图片而产生动画效果;
- 定义逐帧动画的方法:
使用AnimationDrawable对象定义逐帧动画;
它是一个Drawable容器(DrawableContainer),
可以理解为,它事先加载好了一系列的图片;
和普通的Drawable一样,它可以被设为视图对象的背景;
-
最简单的定义逐帧动画的方法,
- 在drawable文件夹下新建一个xml文件;
- 在xml文件中,通过<animation-list>来定义AnimationDrawable对象; 一个<animation-list>对应一个AnimationDrawable对象;
- <animation-list>的下层包含若干个<item>, 即一个帧动画对应的一套的若干个帧图;
- 每一个item设置好每一个帧的图片以及对应的延时; 如此便定义好了AnimationDrawable对象;
-
接着使用AnimationDrawable,
- 在某个Activity或者fragment的布局文件中,开启一个<View>控件, 作为帧动画的展示区域; 可以自由设置这个区域的大小;
- 通过View控件的属性android:background将定义好的AnimationDrawable对象(drawable/xml's name——<animation-list>)设置进来作为View控件的背景;
- 在布局文件对应的Java代码处,实例化这个View控件;
- 通过(AnimationDrawable)view.getBackground();获得view的背景Drawable对象并向下转型为AnimationDrawable对象, 然后赋给一个AnimationDrawable的实例变量引用;
- 使用AnimationDrawable的实例调用start()、stop(),
即可分别做
帧动画的开启和关闭
; - 可以在Activity.java中, 通过animationDrawable.setOneShot(true); 将动画设置为只播放这套帧图一次; 或者给<animation-list>添加android:oneshot="true"属性,也可实现;
-
- 小结: 逐帧动画的基础是帧,也即图片,图片一般由美工制作; 没有原图就无法制作逐帧动画,则应用范围比较小; 将一套帧图设置在<animation-list>(AnimationDrawable)容器中, 并且这个<animation-list>(AnimationDrawable)需要作为一个View的背景(android:background), 依赖View来实现;
- 下面做一个demo:
- 首先新建一个项目,准备好三张图片:
frame_1.png
frame_2.png
frame_3.png
- 在drawable文件夹下新建一个xml文件, 文件目录:
代码语言:javascript复制并编写如下代码: 代码中通过<animation-list>来定义AnimationDrawable对象, 一个animation-list便签对应(映射为)一个AnimationDrawable对象; 每个item为一帧, android:drawable 属性设置帧图; android:duration 设置延时,单位为ms;
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/frame_1"
android:duration="100"/>
<item android:drawable="@drawable/frame_2"
android:duration="100"/>
<item android:drawable="@drawable/frame_3"
android:duration="100"/>
</animation-list>
如此便定义好了AnimationDrawable对象;
- 现在编写xml布局(activity_frame_animation):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FrameAnimationActivity">
<View
android:id="@ id/view"
android:background="@drawable/loading"
android:layout_centerInParent="true"
android:layout_width="300dp"
android:layout_height="300dp"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="@ id/btnStart"
android:text="Start"
android:onClick="onClick"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<Button
android:id="@ id/btnStop"
android:text="Stop"
android:onClick="onClick"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
View组件即帧动画的展示区域; android:background 属性,把方才定义好的AnimationDrawable对象(loading.xml)设置进来; 两个button用来调试动画;
- 接着是FrameAnimationActivity:
public class FrameAnimationActivity extends AppCompatActivity {
private AnimationDrawable animationDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_animation);
View view = findViewById(R.id.view);
//view.getBackground()返回的是一个Drawable对象,在这里已经明确背景是AnimationDrawable,
// 所以可以做一个强制转换(窄化、向下转型)
animationDrawable = (AnimationDrawable)view.getBackground();
}
public void onClick(View view){
switch (view.getId()){
case R.id.btnStart:
animationDrawable.start();
break;
case R.id.btnStop:
animationDrawable.stop();
break;
}
}
}
- 实例化方才设置了AnimationDrawable为背景的View对象;
- 使用view实例getBackground()获得背景;
- view.getBackground()返回的是一个Drawable对象, 在这里已经明确背景是AnimationDrawable, 所以可以做一个强制转换(窄化、向下转型);
- 后面是简单的点击事件: 使用AnimationDrawable的实例调用start()、stop(), 分别做帧动画的开启和关闭;
Tip1 查看继承关系 光标移动到AnimationDrawable上, ctrl h 可以查看继承关系, 我们可以看到AnimationDrawable是Drawable的子类:
查看类的结构
- Windows:ctrl F12
- Mac:cmd F12
查看继承关系
- Windows:ctrl h
- Mac:control h
- 运行效果如下:
- 最后, 可以看到帧动画默认是对设置好的一系列帧图做循环往复的播放的, 可以在Activity.java中,通过animationDrawable.setOneShot(true); 将动画设置为只播放这套帧图一次:
或者给<animation-list>添加android:oneshot="true"属性,也可实现:
3.1 视图动画. 原理
上面说过, 逐帧动画的基础是帧,也即图片,图片一般由美工制作; 没有原图就无法制作逐帧动画,则应用范围比较小; 将一套帧图设置在<animation-list>(AnimationDrawable)容器中, 并且这个<animation-list>(AnimationDrawable)需要作为一个View的背景(android:background), 依赖View来实现;
视图动画
则直接操作视图对象(View、TextView、Button、ImageView), 是之产生对应的动画; 可以令视图对象产生透明度渐变、位移、旋转等效果;
-
对应的类:
- android.view.animation
- Animation
- AlphaAnimation
- ScaleAnimation
- TranslateAnimation
- RotateAnimation
- AnimationSet
-
实现的机制——补间动画:
对于动画, 给定一个视图对象的一套起点参数、一套终点参数和一个过程时长即可, 补间动画根据提供的参数自动地进行一个过程的变换;
-
实现的底层原理:
每个视图对象都有一个变换矩阵
, 用于把视图映射到手机屏幕上, 对这个变换矩阵
在单位时间内做对应的数据变更, 即可以使视图产生各种运动效果;
3.2 视图动画. 透明度动画(AlphaAnimation)
- 建立:可以在xml资源文件中建立,也可以在java文件中建立;
- 每一个<alpha>标签对应一个AlphaAnimation对象;
- 控制视图实现从一个透明度到另一个透明度的变换;
- 下面做一个demo:
- 首先,整理刚才的项目, 帧动画的跟视图动画的我们分包处理, 然后新建一个ViewAnimationActivity空Activity:
- res文件夹下新建anim文件夹,对anim文件夹新建一个资源文件,名为alpha:
编写alpha.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration = "1000"
android:fromAlpha="1.0"
android:toAlpha="0.1"/>
</set>
- 属性说明: android:duration 补间时长 android:fromAlpha 起始透明度 android:toAlpha 终止时透明度 以上,一个简单的透明度动画即准备完毕;
编写布局activity_view_animation.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.ViewAnimationActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@ id/viewAlphaAnimation"
android:layout_gravity="center_horizontal"
android:textSize="50dp"
android:text="Alpha"
android:onClick="onClick"
android:padding="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Large"
android:background="@color/colorPrimary"
android:textColor="@android:color/white"/>
</LinearLayout>
</ScrollView>
这里最外层是一个滚动布局, 然后嵌入线性布局,再嵌入TV,TV用来做AlphaAnimation;
编写ViewAnimationActivity:
代码语言:javascript复制
onClick(View view)//view这里指的是点击了的id为viewAlphaAnimation的TV
public class ViewAnimationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_animation);
}
public void onClick(View view){
switch (view.getId()){
case R.id.viewAlphaAnimation:
Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha);
view.startAnimation(alphaAnimation);
break;
}
}
}
核心代码就两句:
代码语言:javascript复制Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha);
view.startAnimation(alphaAnimation);
- 第一句, 调用AnimationUtils中的loadAnimation(), 把刚才定义好的alpha.xml动画资源文件加载进来, 一参为context,二参为资源文件id;
- 第二句, 要实现动画的视图实例(这里是刚刚编写的TV)调用startAnimation(), 把第一句中加载转换得到的Animation对象设置进来;
至此,便实现AlphaAnimation;
- 以上,是通过xml的方法定义的动画,事实上我们还有一种简洁的定义动画的方法:
- 如下,我们直接在目标视图对应的java文件中, 写下这三行代码, 也就是调用AlphaAnimation构造方法,直接实现动画的创建; setDuration()用来设置动画延时:
运行效果一样:
下面是一个基于源码,关于applyTransformation()方法的知识普及: Animation类继承结构:
我们进入Animation类的源码,可以看到这么一个方法——applyTransformation(),其实这个方法就跟我们方才说的 “每个视图对象都通过一个转换矩阵映射到手机屏幕上” 中的 转换矩阵 有关:
它的不同子类对这个方法进行了不同的实现, 比如我们看一下AlphaAnimation类的源码:
可以看到AlphaAnimation类中applyTransformation()的实现就是调节透明度;
- 另外,我们可以看到,用于开启动画的方法startAnimation()是定义在View类中的:
这其实说明每一个View类对象及其子类对象都可以做视图动画;
- 小结:
- 定义以及使用透明度动画(xml法):
- 建立文件夹res/anim;
- 在其下新建一个xml;
- xml中编写<alpha>标签,指定duration、fromAlpha、toAlpha等属性;
- 在目标视图的java文件处, 调用AnimationUtils.loadAnimation()把上述定义了<alpha>标签的xml加载进来, 转换成Animation对象;
- 目标视图实例以上述转换得到的Animation对象为参数调用startAnimation(), 完成动画开启;
java代码法: AlphaAnimation aa = new AlphaAnimation(1,0); aa.setDuration(1000); view.startAnimation(aa);
3.3 视图动画. 缩放动画(ScaleAnimation)
- 建立:可以在xml资源文件中建立,也可以在java文件中建立;
- 每一个<scale>标签对应一个ScaleAnimation对象;
- 控制视图实现在X轴、Y轴上从一个缩放程度到另一个缩放程度的变换;
- 下面做一个demo: 同理上方,这里简述了;
- res文件夹下新建一个资源文件,名为scale;对其进行编写:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="1000"
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="1.0"/>
</set>
- 属性说明: android:duration 补间时长 android:fromXScale/android:toXScale 起始X轴缩放度比例, 1表示原图比例,即不缩放; android:fromYScale/android:toYScale 起始Y轴缩放度比例 以上,一个简单的缩放动画即准备完毕;
- 值=0.0 :表示收缩到没有
- 值<1.0 :表示收缩
- 值=1.0 :表示无伸缩
- 值>1.0 :表示放大
编写布局activity_view_animation.xml:
Tip2 抽取控件属性为Style文件
- 接着会弹出下面这个窗口,打钩表示要抽取的属性,Style name表示待会儿自动创建的style标签名:
- 点击ok之后便抽取完毕:
- 如下,抽象出来的样式会放在values文件夹下的style.xml文件中,用一个style便签存储起来:
下面是activity_view_animation.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
...
tools:context=".view.ViewAnimationActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@ id/viewAlphaAnimation"
...
style="@style/AnimationTextView" />
<TextView
android:id="@ id/viewScaleAnimation"
android:layout_gravity="center_horizontal"
android:textSize="50dp"
android:text="Scale"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
</LinearLayout>
</ScrollView>
到java文件:
代码语言:javascript复制public class ViewAnimationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
}
public void onClick(View view){
switch (view.getId()){
case R.id.viewAlphaAnimation:
// ...
// view.startAnimation(alphaAnimation);//view这里指的是点击了的id为viewAlphaAnimation的TV
...
break;
case R.id.viewScaleAnimation:
Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);
view.startAnimation(scaleAnimation);
break;
}
}
}
代码同理透明度动画,至此完成设置;
运行:
- 添加一个属性
android:fillAfter="true"
,使动画结束后View组件保持结束时的状态:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true">
<scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="1.0"/>
</set>
效果:
java代码实现:
代码语言:javascript复制case R.id.viewScaleAnimation:
// Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);
// view.startAnimation(scaleAnimation);
ScaleAnimation sa = new ScaleAnimation(1,2,1,1);
sa.setDuration(1000);
view.startAnimation(sa);
Toast.makeText(this,"我是java定义的缩放动画",Toast.LENGTH_SHORT).show();
break;
运行效果同上;
- 动画基准点概念 动画的运作都是有一个基准点的, 而默认的基准点是在目标组件的左上角, 用xml描述即:
把代码改成上图所示如此,运行效果也会跟刚才的一样;
- 当然了,事情没那么简单,基准点的这个参数设置是有讲究的,
默认是设置为0,其实它有三种描述样式,如下:
-
50
:组件本身左边界起,往右(X轴方向)距离50个像素处; -
50%
:组件本身左边界起,往右(X轴方向)距离组件本身宽度的50%长度之处; -
50%p
:组件的父控件左边界起,往右(X轴方向)距离组件其父控件宽度的50%长度之处;
-
demo(修改scale.xml):
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true">
<scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="2.0"
android:pivotX="50%"
android:pivotY="50%"/>
</set>
java:
代码语言:javascript复制ase R.id.viewScaleAnimation:
Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);
view.startAnimation(scaleAnimation);
运行:
java实现:
代码语言:javascript复制case R.id.viewScaleAnimation:
// Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);
// view.startAnimation(scaleAnimation);
ScaleAnimation sa = new ScaleAnimation(1,2,1,2,
Animation.RELATIVE_TO_SELF,0.5F,
Animation.RELATIVE_TO_SELF,0.5F);
sa.setDuration(1000);
sa.setFillAfter(true);
view.startAnimation(sa);
Toast.makeText(this,"我是java定义的缩放动画",Toast.LENGTH_SHORT).show();
break;
运行效果同上;
使用. 小结: 似同透明度动画, xml法则定义动画资源xml文件, 在java处调用loadAnimation()把xml加载进来, 视图实例调用startAnimation()开启动画即可; java定义法,则: ScaleAnimation sa = new ScaleAnimation(1,2,1,1); sa.setDuration(1000); view.startAnimation(sa);
3.4 视图动画. 位移动画(TranslateAnimation)
建立:可以在xml资源文件中建立,也可以在java文件中建立; 每一个<translate>标签对应一个TranslateAnimation对象; 控制视图实现在X轴、Y轴上从一个坐标到另一个坐标的移动变换; 下面做一个demo: 同理上方,这里简述了; res文件夹下新建一个资源文件,名为translate;对其进行编写:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true">
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100%"
android:toYDelta="100%" />
</set>
- 属性说明:
fromXDelta/fromYDelta 从X轴/Y轴起始点
toXDelta/toYDelta 到X轴/Y轴终点
注意这里描述
起始点与终点
的方式似同于上方描述动画基准点
的方式;
Tip3.0 格式化代码功能
这里调整了一下style: <style name="AnimationTextView"> <item name="android:textSize">25dp</item> <item name="android:padding">20dp</item> <item name="android:layout_margin">16dp</item> <item >name="android:textAppearance">@style/Base.TextAppearance.AppCompat.Large</item> <item name="android:background">@color/colorPrimary</item> <item name="android:textColor">@android:color/white</item> </style>
下面是activity_view_animation.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.ViewAnimationActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@ id/viewAlphaAnimation"
android:layout_gravity="center_horizontal"
android:text="Alpha"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
<TextView
android:id="@ id/viewTranslateAnimation"
android:layout_gravity="center_horizontal"
android:text="translate"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
<TextView
android:id="@ id/viewScaleAnimation"
android:layout_gravity="center_horizontal"
android:text="Scale"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
</LinearLayout>
</ScrollView>
java:
代码语言:javascript复制public class ViewAnimationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_animation);
}
public void onClick(View view){
switch (view.getId()){
case R.id.viewAlphaAnimation:
...
break;
case R.id.viewScaleAnimation:
...
case R.id.viewTranslateAnimation:
Animation translateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate);
view.startAnimation(translateAnimation);
break;
}
}
}
运行效果:
Tip 3.1自定义背景样式描边父布局
- 在Drawable文件夹下面新建一个文件,edge.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/transparent"/> <stroke android:color="@android:color/black" android:width="1px"/> </shape> 中心透明,边界线1px宽度黑线 将edge.xml设置为LinearLayout的背景: <LinearLayout android:background="@drawable/edge" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content">
修改translate.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true">
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="50%"
android:toYDelta="100%" />
</set>
activity_view_animation.xml:(视图放在最后一个)
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<ScrollView...
tools:context=".view.ViewAnimationActivity">
<LinearLayout
android:background="@drawable/edge"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
...
<TextView
android:id="@ id/viewTranslateAnimation"
android:layout_gravity="center_horizontal"
android:text="translate"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
</LinearLayout>
</ScrollView>
style:
代码语言:javascript复制<style name="AnimationTextView">
<item name="android:textSize">25dp</item>
<item name="android:padding">20dp</item>
<item name="android:layout_margin">5dp</item>
<item name="android:textAppearance">@style/Base.TextAppearance.AppCompat.Large</item>
<item name="android:background">@color/colorPrimary</item>
<item name="android:textColor">@android:color/white</item>
</style>
运行结果:
我们可以看到动画视图发生了偏移, 但是超出父控件的部分是不能被绘制出来的;(有上面的定制,描边区域内即父控件)
可以知道上文的 缩放动画 其实有一部分是超出了父布局,从而没有显示出来
- 要权宜解决这个问题也很简单, 我们可以在第三个视图下添加一个空白View, 便可以扩大父布局区域, 从而可以看到完整的偏移动画了:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
...
tools:context=".view.ViewAnimationActivity">
<LinearLayout
...
android:padding="16dp">
<TextView
...
style="@style/AnimationTextView" />
<TextView
...
style="@style/AnimationTextView" />
<TextView
android:id="@ id/viewTranslateAnimation"
android:layout_gravity="center_horizontal"
android:text="translate"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
<View
android:layout_width="match_parent"
android:layout_height="200dp"/>
</LinearLayout>
</ScrollView>
运行效果:
使用. 小结: 似同透明度动画,
- xml法 则 1.定义动画资源xml文件, 2.在java处调用loadAnimation()把xml加载进来, 3.视图实例调用startAnimation()开启动画即可;
- java定义法,则:
TranslateAnimation ta = new TranslateAnimation( Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF,0.5F, Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF,1); ta.setFillAfter(true); ta.setDuration(1000); view.startAnimation(ta);
- 其实关于TranslateAnimation 等子类的定义也是大同小异,
大概知道使用方法之后,
可以通过AS查看各个类的源码,
知晓其更多的构造方法,
根据需要使用不同的构造方法定义动画;
3.5 视图动画. 旋转动画(RotateAnimation)
建立:可以在xml资源文件中建立,也可以在java文件中建立; 每一个<rotate>标签对应一个RotateAnimation对象; 控制视图实现在X轴、Y轴上从一个坐标到另一个坐标的移动变换; 下面做一个demo: 同理上方,这里简述了;
res文件夹下新建一个资源文件,名为rotate;对其进行编写:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:duration="1000">
<rotate
android:fromDegrees="0"
android:toDegrees="270"/>
</set>
属性说明: fromDegrees、android:toDegrees :起始、终止角度
- from=负数->to=正数:表示顺时针旋转
- from=负数->to=负数:表示逆时针旋转
- from=正数->to=正数:表示顺时针旋转
- from=正数->to=负数:表示逆时针旋转
activity_view_animation.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
...
tools:context=".view.ViewAnimationActivity">
<LinearLayout
android:background="@drawable/edge"
...>
<TextView
android:id="@ id/viewAlphaAnimation"
.../>
<TextView
android:id="@ id/viewScaleAnimation"
.../>
<TextView
... />
<TextView
android:id="@ id/viewRotateAnimation"
android:layout_gravity="center_horizontal"
android:text="rotate"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
<View.../>
</LinearLayout>
</ScrollView>
ViewAnimationActivity.java:
代码语言:javascript复制 case R.id.viewRotateAnimation:
Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate);
view.startAnimation(rotateAnimation);
运行效果:
Tip4 创建一个简单的菜单刷新按钮 Tip 首先添加一个icon
然后点击ok:
然后点击next,然后finsh,这样之后会在Drawable目录下生成一段vector的xml:
将之设计成白色: <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path android:fillColor="#FFF" android:pathData="M12,6v3l4,-4 -4,-4v3c-4.42,0 -8,3.58 -8,8 0,1.57 0.46,3.03 1.24,4.26L6.7,14.8c-0.45,-0.83 -0.7,-1.79 -0.7,-2.8 0,-3.31 2.69,-6 6,-6zM18.76,7.74L17.3,9.2c0.44,0.84 0.7,1.79 0.7,2.8 0,3.31 -2.69,6 -6,6v-3l-4,4 4,4v-3c4.42,0 8,-3.58 8,-8 0,-1.57 -0.46,-3.03 -1.24,-4.26z"/> </vector>
Tip 建立菜单文件夹 & 文件
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@ id/renew" android:title="Renew" app:showAsAction = "always" android:icon="@drawable/ic_autorenew_black_24dp"/> </menu> 接着回java文件编写加载布局以及点击事件:
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.renew, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.renew: recreate(); break; } return super.onOptionsItemSelected(item); } 运行,结果如下(点击刷新按钮,Activity重建“刷新”):
- 旋转动画同样可以设置基准点
- 下面的代码表示让视图以本身中点为旋转中心旋转无限次,
每次的时长为300ms:
android:repeatCount
属性可以指定重复次数; 如android:repeatCount=3
便是重复3次;
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<rotate
android:duration="1000"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="360"
android:repeatCount="infinite"/>
</set>
- 另外还有一个属性
android:repeatMode
: 即决定, 下次开始的时候,以什么样的方式开始——重新开始还是原路返回: 这个属性默认值是restart,即android:repeatMode="restart",即重新开始; 我们用为位移动画来诠释: 更改translate.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<translate
android:duration="2000"
android:repeatCount="1"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="80%p"
android:toYDelta="0" />
</set>
- 运行,效果如下:
其中位移动画android:repeatCount="1",则一轮动画之后又重复了一次; 下次动画开始的时候,是重新开始的方式开始, 也即方才说的 默认android:repeatMode="restart";
- 以及,其中旋转动画是方才android:repeatCount="infinite"部分的代码的效果;
- 现在更改translate.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<translate
android:duration="2000"
android:repeatCount="1"
android:repeatMode="reverse"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="80%p"
android:toYDelta="0" />
</set>
运行,效果如下:
- 即下次动画开始的时候,是原路返回的方式开始;
使用. 小结: 似同透明度动画,
- xml法 则 1.定义动画资源xml文件, 2.在java处调用loadAnimation()把xml加载进来, 3.视图实例调用startAnimation()开启动画即可;
- java定义法,则:
case R.id.viewTranslateAnimation: TranslateAnimation ta = new TranslateAnimation( Animation.RELATIVE_TO_PARENT,0, Animation.RELATIVE_TO_PARENT,(0.8F), Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF,0); ta.setRepeatCount(1); ta.setRepeatMode(REVERSE); ta.setFillAfter(true); ta.setDuration(2000); view.startAnimation(ta); break; case R.id.viewRotateAnimation: RotateAnimation ra = new RotateAnimation(0,360, Animation.RELATIVE_TO_SELF,0.5F, Animation.RELATIVE_TO_SELF,0.5F); ra.setDuration(1000); ra.setFillAfter(true); ra.setRepeatCount(INFINITE); view.startAnimation(ra); break; 效果跟方才的动画效果是一样的;
3.6 集合动画
建立:可以在xml资源文件中建立,也可以在java文件中建立; 每一个<set>标签对应一个AnimationSet对象; 控制视图实现复合动画; 下面做一个demo: 同理上方,这里简述了;
res文件夹下新建一个资源文件,名为set.xml ;对其进行编写:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:duration = "1000"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="720"/>
<translate
android:duration="1000"
android:fromXDelta="0"
android:toXDelta="500"
android:fromYDelta="0"
android:toYDelta="0"/>
</set>
activity_view_animation.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<ScrollView ...>
<LinearLayout...>
<TextView
...
<TextView
android:id="@ id/viewSetAnimation"
android:text="Set"
android:onClick="onClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnimationTextView" />
<View
android:layout_width="match_parent"
android:layout_height="200dp"/>
</LinearLayout>
</ScrollView>
ViewAnimationActivity.java:
代码语言:javascript复制 case R.id.viewSetAnimation:
Animation setAnimation = AnimationUtils.loadAnimation(this, R.anim.set);
view.startAnimation(setAnimation);
运行效果:
修改set.xml,给<translate>增加属性android:startOffset="1000"
(属性说明:即整个复合动画开始1000ms后,再运行<translate>中的内容):
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
.../>
<translate
...
android:startOffset="1000"
.../>
</set>
运行效果:
- java方法(能实现,但是有误差,不推荐):
case R.id.viewSetAnimation:
AnimationSet as = new AnimationSet(true);
as.setDuration(2000);
RotateAnimation ra1 = new RotateAnimation(0,720,
Animation.RELATIVE_TO_SELF,0.5F,
Animation.RELATIVE_TO_SELF,0.5F);
ra1.setDuration(1000);
as.addAnimation(ra1);
TranslateAnimation ta1 = new TranslateAnimation(0,500,0,0);
ta1.setDuration(1000);
ta1.setStartOffset(1000);
as.addAnimation(ta1);
view.startAnimation(as);
3.7 插值器
- 在定义动画的时候可以通过设置插值器, 来设置动画在不同时间点的不同变化率; (变化率即动画完成进度同动画完成所需时间的微分)
- Android内置了 9 种内置的插值器实现:插值器与估值器
- 另外有一个网站可以模拟插值器的变化过程;
- 插值器的设置方法: 0.定义控件:
<View
android:id="@ id/viewAccelerate"
android:onClick="onClick"
style="@style/InterpolatorView" />
<View
android:id="@ id/viewLinear"
android:alpha="0.5"
android:onClick="onClick"
style="@style/InterpolatorView" />
(这里其实跟前面的动画定义都差不多,只是多了一步设置插值器)
- 加载动画xml;(AnimationUtils.loadAnimation()) 2.设置插值器;(setInterpolator()) 3.开启动画;(startAnimation())
case R.id.viewAccelerate:
View viewAccelerate = findViewById(R.id.viewAccelerate);
View viewLinear = findViewById(R.id.viewLinear);
Animation animationLinear = AnimationUtils.loadAnimation(this,R.anim.translate);
Animation animationAccelerate = AnimationUtils.loadAnimation(this,R.anim.translate);
animationLinear.setInterpolator(new LinearInterpolator());
animationAccelerate.setInterpolator(new AccelerateInterpolator());
viewLinear.startAnimation(animationLinear);
viewAccelerate.startAnimation(animationAccelerate);
break;
- 或者这样定义:
- 创建动画实例; 2.设置插值器;(setInterpolator()) 3.开启动画;(startAnimation())
Animation alphaAnimation = new AlphaAnimation(1,0);
// 步骤1:创建透明度动画的对象 & 设置动画效果
alphaAnimation.setDuration(3000);
alphaAnimation.setInterpolator(new OvershootInterpolator());
// 步骤2:给动画设置插值器
view.startAnimation(alphaAnimation);
// 步骤3:开启动画
运行效果:
Tip5 duration的默认值
Android给duration封装了几个默认值,能够设置更形象的动画时长;
- 本文内容参考自 慕课网. 就业班