如果您对css变换与动画详解感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于css变换与动画详解的详细内容,我们还将为您解答css变换与动画详解的区别的相关问题,并且为您提供
如果您对css变换与动画详解感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于css变换与动画详解的详细内容,我们还将为您解答css变换与动画详解的区别的相关问题,并且为您提供关于3D CSS变换,Firefox中的锯齿边、Android Animation动画详解(二): 组合动画特效_html/css_WEB-ITnose、Android 动画详解:属性动画、View 动画和帧动画、Android动画教程之属性动画详解的有价值信息。
本文目录一览:- css变换与动画详解(css变换与动画详解的区别)
- 3D CSS变换,Firefox中的锯齿边
- Android Animation动画详解(二): 组合动画特效_html/css_WEB-ITnose
- Android 动画详解:属性动画、View 动画和帧动画
- Android动画教程之属性动画详解
css变换与动画详解(css变换与动画详解的区别)
举个栗子:
--------元素整体居中
.Box{
position:absolute;top:50%;left:50%;
width:50px;
height:50px;
transform:translate(-50%,-50%);
background:gray;
}
1.translate:移动,是transform的一个方法
通过 translate() 方法,元素从其当前位置移动,根据给定的 left(x 坐标) 和 top(y 坐标) 位置参数:
用法transform: translate(50px,100px);
-ms-transform: translate(50px,100px);
-webkit-transform: translate(50px,100px);
-o-transform: translate(50px,100px);
-moz-transform: translate(50px,100px);
2.transform:变形,改变
CSS3中主要包括:
在CSS3中transform主要包括以下几种:旋转rotate、扭曲skew、缩放scale和移动translate以及矩阵变形matrix。
旋转:rotate() 顺时针旋转给定的角度,允许负值 rotate(30deg)
扭曲:skew() 元素翻转给定的角度,根据给定的水平线(X 轴)和垂直线(Y 轴)参数:skew(30deg,20deg)
缩放:scale() 放大或缩小,根据给定的宽度(X 轴)和高度(Y 轴)参数: scale(2,4)
移动:translate() 平移,传进 x,y值,代表沿x轴和y轴平移的距离
所有的2D转换方法组合在一起: matrix() 旋转、缩放、移动以及倾斜元素
matrix(scale.x,scale.y,translate.x,translate.y)
改变起点位置 transform-origin: bottom left;
transform: rotate 旋转| scale 缩放| skew扭曲 | translate移动 |matrix矩阵变形;
综合起来使用:transform: 30deg 1.5 30deg 20deg 100px 200px;//需要有空格隔开
3.transition: 允许CSS属性值在一定的时间区间内平滑的过渡。(过渡动画)
Transition作用是指定了某一个属性(如width、left、transform等)在两个值之间如何过渡。
如果某一个元素指定了Transiton,那么当其某个属性改变的时候就会按照Transition指定的方式进行过渡,动画就这么产生了。
transition主要包含四个属性值:
(1)执行变换的属性:transition-property;
(2)变换延续的时间:transition-duration;
(3)在延续时间段,变换的速率变化:transition-timing-function //例:平缓进入、先快后慢;
(4)变换延迟时间:transition-delay。
需要事件的触发,例如单击、获取焦点、失去焦点等。
语法:transition:property duration timing-function delay;
例如:transition:width 2s ease 0s;
4.Animation
Animation也是通过指定某一个属性(如width、left、transform等)在两个值之间如何过渡来实现动画的,
与Transition不同的是:
1.Animation可以通过keyframe显式控制当前帧的属性值,而Transition只能隐式来进行
(不能指定每帧的属性值),所以相对而言Animation的功能更加灵活;
2.Animation通过模拟属性值改变来实现动画,动画结束之后元素的属性没有变化;而Transition确实改变了元
素的属性值,动画结束之后元素的属性发生了变化;这一点,这在实际应用中会产生很大的区别。
Animation模块包括了animation-name、animation-duration、animation-timing-function、
animation-delay、animation-iteration-count、animation-play-state等属性。
animation详解:
什么是css3中的动画:
使元素从一种样式逐渐变化为另一种样式
可以改变任意多的样式任意多的次数
可以用百分比规定变化发生的时间,或者用关键词“from”和“to”,等价于“0%”和“100%”,表示动画的开始和完成
通过css3我们可以创建动画,可以代替页面中的动画图片、Flash动画以及JavaScript。
如果创建css动画,需要了解@keyframes规则。
@keyframes规则用于创建动画,在其中规定某项css样式,就能创建由当前样式逐渐改为新样式的动画效果。
兼容性:
Internet Explorer 10、Firefox 以及 Opera 支持 @keyframes 规则和 animation 属性。
Chrome 和 Safari 需要前缀 -webkit-。
注释:Internet Explorer 9,以及更早的版本,不支持 @keyframe 规则或 animation 属性。
实现:
在 @keyframes 中创建动画时,要将其捆绑到某个选择器,否则不会产生动画效果。
需要至少规定以下两项:
规定动画的名称
规定动画的时长
示例:<!DOCTYPE html><html><head><style> div{width:100px;height:100px;background:red;animation:myfirst 5s;/*兼容处理*/-moz-animation:myfirst 5s; /* Firefox */-webkit-animation:myfirst 5s; /* Safari and Chrome */-o-animation:myfirst 5s; /* Opera */} /*定义动画----myfirst是动画的名称*/@keyframes myfirst{from {background:red;}to {background:yellow;}} @-moz-keyframes myfirst /* Firefox */{from {background:red;}to {background:yellow;}} @-webkit-keyframes myfirst /* Safari and Chrome */{from {background:red;}to {background:yellow;}} @-o-keyframes myfirst /* Opera */{from {background:red;}to {background:yellow;}}</style></head><body> <div></div></body></html>
3D CSS变换,Firefox中的锯齿边
解决方法
“解决方法”,添加透明轮廓属性:
outline: 1px solid transparent;
在Firefox 10.0.2 Windows 7:http://jsfiddle.net/nKhr8/上测试
原始答案:(背景颜色依赖)
“解决方法”,添加与您的背景颜色相同的边框属性(白色情况下):
border: 1px solid white;
在Firefox 10.0.2 Windows 7:http://jsfiddle.net/LPEfC/上测试
Android Animation动画详解(二): 组合动画特效_html/css_WEB-ITnose
前言
上一篇博客android animation动画详解(一): 补间动画 我已经为大家介绍了android补间动画的四种形式,相信读过该博客的兄弟们一起都了解了。如果你还不了解,那点链接过去研读一番,然后再过来跟着我一起学习如何把简单的动画效果组合在一起,做出比较酷炫的动画特效吧。
如题,大家想想,如果一个页面上包含了许多动画,这些动画要求按顺序播放,即一个动画播放完成后,继续播放另一个动画,使得这些动画具有连贯性。那该如何实现呢? 有开发经验或者是逻辑思维的人肯定会想,对动画进行监听啊,如果这个动画播放完了,再去播放另一个动画不就好了。
Congratulations, 你和我想的是一样一样的。
我们看下通过这种动画播放监听如何去做:
立即学习“前端免费学习笔记(深入)”;
private void continueAnim(){ // 先加载第一个动画 Animation translate = AnimationUtils.loadAnimation(getActivity(), R.anim.translate_animation); // 在加载第二个动画 final Animation scale = AnimationUtils.loadAnimation(getActivity(), R.anim.scale_animation); // 接下来,我们队第一个动画进行监听,当它播放完成后,我们播放第二个动画 translate.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { imgView.startAnimation(scale); } @Override public void onAnimationRepeat(Animation animation) { } }); imgView.startAnimation(translate); }
注释我已经写得挺详细了,可以说,这种方法so easy,没啥可说的。
除了上面介绍的使用监听器监听动画播放结束之外,还有一个更easy方法,也是我们优先推荐使用的,那就是Animation Set。
这里,我们要引入一个动画的属性:startOffset。 如何去使用呢?看下定义动画的代码:
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:fillafter="true" android:fillenabled="true"><alpha android:fromalpha="0" android:toalpha="1" android:duration="3000"></alpha><translate android:duration="1000" android:fromxdelta="0" android:fromydelta="0" android:toxdelta="100" android:toydelta="100" android:startoffset="3000"></translate></set>
仔细看下translate定义的动画,它其中就有一个属性startOffset,这个属性的值,其实就是alpha动画的duration的值,他的意思是,延迟三秒后播放,其实也就是第一个alpha动画播放完成后再播放。
Animation continueAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.continue_animation);imgView.startAnimation(continueAnim);
好啦,写到这,让我们看下运行的效果吧:
重播动画,故名思议,就是动画重复播放。大家看下上面那个gif的动态图,其实就是重复播放动画。那Android如何重复播放动画呢?
其实very easy,因为Android本身为定义动画提供了两个属性repeatCount和repeatMode,只要为你的动画设置上这两个属性,那就ok了!
为了方便记忆,让我们稍微看下代码吧:
<translate android:duration="1000" android:fromxdelta="0" android:fromydelta="0" android:toxdelta="100" android:toydelta="100" android:repeatcount="5" android:repeatmode="restart"></translate>
这里我们指定了 repeatCount为5,则动画要播放5次,repeatMode为“restart”,则动画每次都是重复播放。repeatMode还有个取值“reverse”,这是指让动画倒叙播放。 看下效果。
说道Activity切换动画,我想大家肯定都不陌生,比如你玩淘宝、美团啥的,你会发现它们的页面切换都是从右向左滑动进入的,这其实就是Activity切换动画的应用。或许大家初始会觉得挺难,但我要告诉你的是,其实这玩意真简单,如果你已经会了如何定义动画(特指补间动画),那么你只要再理解下一个方法??overridePendingTransition即可。
先让我们一起看下这个方法的定义:
/** * @param enterAnim A resource ID of the animation resource to use for * the incoming activity. Use 0 for no animation. * @param exitAnim A resource ID of the animation resource to use for * the outgoing activity. Use 0 for no animation. */ public void overridePendingTransition(int enterAnim, int exitAnim) { try { ActivityManagerNative.getDefault().overridePendingTransition( mToken, getPackageName(), enterAnim, exitAnim); } catch (RemoteException e) { } }
接下来让我们定义两个动画资源:fade_in.xml和hold_out.xml
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"><alpha android:fromalpha="0.2" android:toalpha="1.0" android:duration="1000"></alpha></set>
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"><translate android:fromxdelta="0%p" android:toxdelta="100%p" android:duration="1000"></translate></set>
定义动画结束后,那我们只需要在启动新Activity或者结束Activity时,复写 overridePendingTransition方法,并传入动画就好啦:
Intent intent = new Intent(getActivity(),SecondActivity.class);startActivity(intent);overridePendingTransition(R.anim.fade_in,R.anim.hold_out);
或者是:
public void back(View view){ finish(); overridePendingTransition(R.anim.fade_in,R.anim.hold_out);}
有没有被惊叹道,原来就这么easy啊! 赶快自己也动手试下吧。
其实Android简单的动画就这么些个,复杂的动画无非也是把这些动画整合在一起使用而已,大家遇到复杂的动画不要太慌,只要分析清楚它的实现原理,一步步的来解锁,都是可以搞定的啦。
之后,我会再写两篇博客,介绍我在开发过程中使用过的两次动画,当然,并不是很难的那种,只是分享经验而已,敬请期待,欢迎指点。
源码下载地址(免费):http://download.csdn.net/detail/zuiwuyuan/9047739
版权声明:本文为博主原创文章,未经博主允许不得转载。
Android 动画详解:属性动画、View 动画和帧动画
在 Android 中,基本的动画共有三种类型:
- View 动画:也叫视图动画或者补间动画,主要是指
android.view.animation
包下面的一些类,只能被用来设置给 View,缺点是比如当控件移动之后,接收点击的控件的位置不会跟随移动,并且能够实现的效果只有移动、缩放、旋转和淡入淡出操作四种及其组合。 - Drawable 动画:也叫 Frame 动画或者帧动画,其实可以划分到视图动画的类别,实现方式是将一些列的 Drawable 像幻灯片一样一个一个地显示。
- Property 动画: 属性动画主要是指
android.animation
包下面的一些类,只对API 11
以上版本的Android 系统才有效,但我们可以通过兼容库做低版本兼容。这种动画可以设置给任何 Object,包括那些还没有渲染到屏幕上的对象。这种动画是可扩展的,可以让你自定义任何类型和属性的动画。
文末有免费福利哦
1、Drawable 动画
在这里,我们先对 Drawable 动画进行讲解,因为它相对于后面的两种动画比较简单。在示例程序我们准备了一系列图片资源,并在 drawable 文件夹下面定义了动画资源 record_anim.xml:
<?xml version="1.0" encoding="utf-8"?>
<animation-list android:oneshot="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/record0" android:duration="500"/>
<item android:drawable="@drawable/record1" android:duration="500"/>
<item android:drawable="@drawable/record2" android:duration="450"/>
<item android:drawable="@drawable/record3" android:duration="400"/>
<item android:drawable="@drawable/record4" android:duration="350"/>
<item android:drawable="@drawable/record5" android:duration="400"/>
<item android:drawable="@drawable/record6" android:duration="400"/>
</animation-list>
复制代码
然后,我们在代码中使用该资源,并将其赋值给 ImageView。然后,我们从该控件中获取该 Drawable 并将其转换成 AnimationDrawable,随后我们调用它的 start()
方法就开启了 Drawable 动画:
getBinding().ivRecord.setImageResource(R.drawable.record_anim);
animDraw = (AnimationDrawable) getBinding().ivRecord.getDrawable();
animDraw.start();
复制代码
此外,我们可以调用该 Drawable 的 stop()
方法停止动画。
帧动画的注意事项
使用帧动画的时候要注意设置的图片不宜过多、过大,以防止因为内存不够而出现 OOM。
2、View 动画
2.1 基本 View 动画
该动画的资源处在 android.view.animation
包下,主要有以下几个类,它们都继承自 Animation
,我们可以使用它们来实现复杂的动画。这些动画类分别有对应的 xml 标签,所以,我们可以在 xml 中定义动画,也可以在代码中实现动画效果。这里的 AnimationSet
可以用来将多个动画效果进行组合,各预定义动画的对照可以参考下面这张图表:
2.2 View 动画属性
当然,要实现一种动画效果会有许多属性需要指定,在 xml 中,我们用标签的属性指定,在代码中我们用对象的 setter 方法指定。于是,我们可以得到下面这个对应关系:
上面的对应关系是所有的 View 动画共用的,对各个具体的动画类型还有其独有的属性。你可以在各个动画的构造方法中,通过它们从 AttributeSet
中获取了哪些字段来了解它们都定义了哪些属性,这里我们不对其一一进行说明。各预定义的属性动画分别按照不同的方式实现了 Animation
的 applyTransformation
方法,具体的这些属性如何使用以及 View 动画的效果是如何实现的,都可通过阅读该方法的定义得知。
对于 AnimationSet
,它内部维护了一个 Animation
列表,并且其本身也是一个 Animation
,所以,AnimationSet
内部可以添加子 AnimationSet
。
文末有免费福利哦
2.3 插值器
上文中我们提到过,View 动画的具体实现是通过覆写 Animation
的 applyTransformation
方法来完成的。这里我们以 AlphaAnimation
为例来看它是如何作用的,同时你应该注意插值器的作用原理。该方法会在 Animation
中被循环调用,调用的时候会根据插值器计算出一个时间,并将其传递到 applyTransformation
方法中。
Animation
的 getTransformation
方法片段:
if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
if (!mStarted) {
fireAnimationStart();
mStarted = true;
if (NoImagePreloadHolder.USE_CLOSEGUARD) {
guard.open("cancel or detach or getTransformation");
}
}
if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if (mCycleFlip) {
normalizedTime = 1.0f - normalizedTime;
}
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
}
复制代码
AlphaAnimation
的 applyTransformation
方法:
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float alpha = mFromAlpha;
t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
}
复制代码
显然,这里的 interpolatedTime
的是一个比例。比如,假如一个透明动画需要持续 10s
,透明度需要从 0.5f
到 1.0f
,而插值的规则是一个二次函数。那么第 t (0<t<10)
秒的时候控件的透明度应该是:
alpha = 0.5f + (1.0f - 0.5f) * t^2 / 100
复制代码
以上就是插值器的作用原理,你也可以按照自己的需求实现自己的插值器,从而实现期待的动画效果。
2.4 使用 View 动画
作为一个例子,这里我们实现一个让控件抖动的动画。在 anim 文件夹下面,我们定义一个平移的动画,并使用插值器使其重复:
anim/shake.xml
的定义:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="700"
android:fromXDelta="0.0"
android:interpolator="@anim/cycle_7"
android:toXDelta="15.0" />
复制代码
插值器 anim/cicle_7.xml
的定义:
<?xml version="1.0" encoding="utf-8"?>
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:cycles="4.0" />
复制代码
然后,我们在代码中加载 Animation
并调用控件的 startAnimation()
方法开启动画:
getBinding().v.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake));
复制代码
对于 View
,我们有 startAnimation()
用来对 View
开始动画;有 clearAnimation()
用来取消 View
在执行的动画。
不使用 xml,仅使用代码我们一样可以实现上述的效果,这里我们不再进行说明。
2.5 View 动画的特殊使用场景
2.5.1 LayoutAnimation
LayoutAnimation
作用于 ViewGroup
,可以使其子元素出场时都均有某种动画效果,通常用于 ListView
。我们可以像下面这样定义布局动画:
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
android:delay="500"
android:animation="@anim/shake"
xmlns:android="http://schemas.android.com/apk/res/android" />
复制代码
显然,这里我们需要引用一个其他的动画。然后,我们可以在 ListView
的 layoutAnimation
属性中指定布局动画。或者调用 ListView
的 setLayoutAnimation()
方法应用上述动画。
2.5.2 Activity 切换
我们可以通过在 Activity
中调用 overridePendingTransition(R.anim.shake, R.anim.shake);
方法来重写 Activity
的切换动画。注意这个方法应该在 startActivity(Intent)
或者 finish()
之后立即调用。
3、属性动画
3.1 基础梳理
我们可以对比 View 动画来学习属性动画。
- 属性动画主要是指
android.animation
包下面的一些类。 - 属性动画基础的动画类是
Animator
;属性动画也为我们提供了几个预定义的类:AnimatorSet
,ObjectAnimator
,TimeAnimator
和ValueAnimator
;这几个预定义类之间的继承关系是,AnimatorSet
和ValueAnimator
直接继承自Animator
,而ObjectAnimator
和TimeAnimator
继承自ValueAnimator
。 - 与 View 动画不同的是,属性动画的使用范围更加宽泛,它不局限于 View,本质上它是通过修改控件的属性值实现的动画。当你尝试对某个对象的某个属性进行修改的时候会有一些限制,即属性动画要求该对象必须提供了该属性的
setter
方法。 - 属性动画也有
xml
和代码两种定义方式,它的xml
通常定义在animator
文件夹下面,而 View 动画定义在anim
文件夹下面。 - 属性动画提供了类似于
AnimationUtils
的方法用来从布局文件夹中加载属性动画:AnimatorInflater
类的loadAnimator()
方法。 - 属性动画也有自己的插值器:
TimeInterpolator
,并且也提供了几个预定义的插值器。 - 我们也可以调用
View
的方法来使用属性动画,我们可以通过 View 的animate()
方法获取一个ViewPropertyAnimator
,然后调用ViewPropertyAnimator
的其他方法进行链式调用以实现复杂的属性动画效果。
下面是属性动画的代码实现和 xml
实现两种方式的对比:
上文中,我们总结了属性动画的一些知识,并将其与 View 动画进行了对比。这里是一个简单的梳理,在下文中我们会对属性动画进行更加详细的介绍。
3.2 使用属性动画
3.2.1 ValueAnimator
上面说过 ValueAnimator
是 ObjectAnimator
和 TimeAnimator
的基类,我们可以这样使用它:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
Log.d("TAG", "cuurent value is " + currentValue);
}
});
anim.start();
复制代码
这里我们使用 log
输出了值渐变的过程,从日志中可以看出它的效果是值从 0
不断递增直到 1
。如果我们在这个监听方法中根据值修改控件的属性一样可以实现动画效果。除了 ofFloat()
还有 ofInt()
等方法,它们的效果相似。
3.2.2 ObjectAnimator
上面,如果我们想要实现动画效果,需要在 ValueAnimator
的监听事件中修改对象的属性,这里的 ObjectAnimator
,我们只需要传入对象实例和属性的字符串名称,修改对象属性的操作就可以自动完成。比如下面的程序的效果是控件 textview
的透明度会在 5s
之内从 1 变成 0 再变回 1.
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
复制代码
注意这里我们传入的是 alpha
,这个字段本身并不存在于控件中,而是有一个 setAlpha()
的方法。也就是说,ObjectAnimator
作用的原理是通过反射触发 setter
方法而不是修改属性来实现的。你可以在类 PropertyValuesHolder
中更详细地了解这方面的内容。
PropertyValuesHolder
包装了我们要修改的属性的对象和方法等信息,然后会使用反射触发指定对象的方法来完成对对象属性的修改。其中
void setupSetter(Class targetClass) {
Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}
复制代码
会去寻找我们要修改属性的 setter
方法,然后
void setAnimatedValue(Object target) {
if (mProperty != null) {
mProperty.set(target, getAnimatedValue());
}
if (mSetter != null) {
try {
mTmpValueArray[0] = getAnimatedValue();
mSetter.invoke(target, mTmpValueArray);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
Log.e("PropertyValuesHolder", e.toString());
}
}
}
复制代码
会去触发 setter
方法,以修改对象的属性。
文末有免费福利哦
3.2.3 AnimatorSet
AnimatorSet
内部提供了一个构建者 AnimatorSet.Builder
来帮助我们构建组合动画,AnimatorSet.Builder
提供了下面四种方法:
after(Animator anim)
:将现有动画插入到传入的动画之后执行after(long delay)
:将现有动画延迟指定毫秒后执行before(Animator anim)
:将现有动画插入到传入的动画之前执行with(Animator anim)
:将现有动画和传入的动画同时执行
当我们调用 AnimatorSet
的 play()
方法的时候就能获取一个 AnimatorSet.Builder
实例,然后我们就可以使用构建者的方法进行链式调用了:
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();
复制代码
3.2.4 TypeEvaluator
正如前文所述,属性动画也有自己的插值器,我们可以通过插值函数指定在某个时间段内属性改变的速率。插值函数得到的是一个比例,是没有意义的。在 View 动画的 AlphaAnimation
中,如果我们指定了起止的透明度,那么我们可以通过透明度的计算规则得到某个时刻的透明度。但是对于属性动画,因为它可以应用于任何属性,这个属性又可能是任何类型的,那么这个属性将采用什么样的计算规则呢?这就需要我们使用 TypeEvaluator
来指定一个计算规则。也就是说,TypeEvaluator
是属性动画的属性的计算规则。
下面是 TypeEvaluator
的定义,这里的三个参数的含义分别是,fraction
是当前的比例,可以通过插值器计算得到;startValue
和 endValue
分别是属性变化的起止值。它的返回结果就是在某个时刻某个属性的值。
public interface TypeEvaluator<T> {
public T evaluate(float fraction, T startValue, T endValue);
}
复制代码
属性动画中已经为我们提供了几个预定义的 TypeEvaluator
,比如 FloatEvaluator
:
public class FloatEvaluator implements TypeEvaluator<Number> {
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}
复制代码
在属性动画的 PropertyValuesHolder
中会根据属性的类型选择预定义的 TypeEvaluator
。但是如果我们的属性的类型不在预定义的范围之内就需要自己实现一个 TypeEvaluator
。下面我们以日期类型为例来实现一个 TypeEvaluator
。
当我们使用 ValueAnimator
的 ofObject()
方法获取 ValueAnimator
实例的时候,要求我们传入一个 TypeEvaluator
,于是我们可以像下面这样定义:
private static class DateEvaluator implements TypeEvaluator<Date> {
@Override
public Date evaluate(float fraction, Date startValue, Date endValue) {
long startTime = startValue.getTime();
return new Date((long) (startTime + fraction * (endValue.getTime() - startTime)));
}
}
复制代码
然后,我们可以这样使用它:
ValueAnimator animator = ValueAnimator.ofObject(new DateEvaluator(), new Date(0), new Date());
animator.setDuration(5000);
animator.addUpdateListener(animation -> {
Date date = (Date) animation.getAnimatedValue();
LogUtils.d(date);
});
animator.start();
复制代码
这样就可以得到在 5s 之内输出的从时间戳为0,到当前时刻的所有的日期变化。
3.2.5 TimeInterpolator
就像 View 动画一样,我们可以为属性动画指定一个插值器。插值器的作用是用来设置指定时间段内数值的变化的速率。在属性动画中,插值器是 TimeInterpolator
,同样也有几个默认的实现:
AccelerateDecelerateInterolator
:先加速后减速。AccelerateInterpolator
:加速。DecelerateInterpolator
:减速。AnticipateInterpolator
:先向相反方向改变一段再加速播放。AnticipateOvershootInterpolator
:先向相反方向改变,再加速播放,会超出目标值然后缓慢移动至目标值,类似于弹簧回弹。BounceInterpolator
:快到目标值时值会跳跃。CycleIinterpolator
:动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)。LinearInterpolator
:线性均匀改变。OvershottInterpolator
:最后超出目标值然后缓慢改变到目标值。
3.2.6 在 xml 中使用属性动画
我们可以像下面这样定义一个属性动画,
<set android:ordering=["together" | "sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<set>
...
</set>
</set>
复制代码
这里的android:ordering
用于控制子动画启动方式是先后有序的还是同时进行,两个可选参数: sequentially
表示动画按照先后顺序;together
(默认)表示动画同时启动。
这里的 <objectAnimator>
标签的含义如下:
这样在 XML 中定义了属性动画之后,我们可以在代码中通过工具类获取到动画实例并使用:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.animtor.property_animator);
set.setTarget(myObject);
set.start();
复制代码
4、使用动画的注意事项
- 内存耗尽:使用帧动画的时候防止因为图片过多导致 OOM。
- View 动画并没有真正改变 View 的位置:
View
动画并没有真正改变View
的属性,即View
动画执行之后并未改变View
的真实布局属性值。譬如我们在布局中有一个Button
在屏幕上方,我们设置了平移动画移动到屏幕下方然后保持动画最后执行状态呆在屏幕下方,这时如果点击屏幕下方动画执行之后的Button
是没有任何反应的,而点击原来屏幕上方没有Button
的地方却响应的是点击Button
的事件。 - 内存泄漏:使用属性动画的时候,当使用无限循环动画,需要在 Activity 退出的时候停止动画,不然可能会因为无法释放资源而导致 Activity 内存泄漏。
- 动画兼容:当 APP 需要兼容到 API 11 以下的时候就需要注意动画的兼容问题。
- 使用 dp 而不是 px:因为
px
在不同设备上面的兼容问题,使用动画的时候尽量使用dp
作为单位。 - 硬件加速:使用硬件加速可以提升动画的流畅性。
源代码
你可以在Github获取以上程序的源代码: Android-references。
最后给大家分享一份非常系统和全面的Android进阶技术大纲及进阶资料,及面试题集
想学习更多Android知识,请加入Android技术开发企鹅交流 7520 16839
进群与大牛们一起讨论,还可获取Android高级架构资料、源码、笔记、视频
包括 高级UI、Gradle、RxJava、小程序、Hybrid、移动架构、React Native、性能优化等全面的Android高级实践技术讲解性能优化架构思维导图,和BATJ面试题及答案!
群里免费分享给有需要的朋友,希望能够帮助一些在这个行业发展迷茫的,或者想系统深入提升以及困于瓶颈的朋友,在网上博客论坛等地方少花些时间找资料,把有限的时间,真正花在学习上,所以我在这免费分享一些架构资料及给大家。希望在这些资料中都有你需要的内容。
Android动画教程之属性动画详解
简介
Android 开发中,总是需要一些动画来优化用户的交互体验,提高用户满意度。因此,Google 为我们提供了一些用于处理动画效果的动画框架。Android 的动画框架分为两类:
- 传统动画(Animation):通过系统不断调用onDraw方法重绘界面,来达到动画的效果。
- 属性动画(Animator):通过操纵一个属性的get/set方法,真实地改变目标的某些属性。
传统动画框架的局限性
既然有了传统动画框架,Google 为什么还要创造一个属性动画框架呢?
我们下面举个例子来说明一下传统动画的局限性。
在布局中加入一个 ImageView 和一个 Button,点击 ImageView 后弹出一个 Toast,点击 Button 后使 ImageView 展现一个向右平移的动画效果。
下面是使用传统动画实现的代码:
TranslateAnimation animation = new TranslateAnimation(0,200,0,0); // 平移动画x轴移动200,y轴不动 animation.setDuration(1000); // 动画时长 animation.setFillAfter(true); // 使动画结束后停留在结束的位置 mIvPicture.startAnimation(animation);
运行后,ImageView 确实进行了我们预期的平移的效果。可是当我们尝试点击 ImageView 当前的位置时,却没有 Toast 弹出。我们再尝试去点击 ImageView 开始动画前的位置,却成功弹出了 Toast。
这就是传统动画很大的局限性:
- 它仅仅是重绘了控件,改变了其显示的位置。但真正事件响应的位置,却并没有发生改变。因此传统动画不适合做具有交互的动画效果。仅仅能做一些显示的动画效果。
- 传统动画是不断通过 onDraw() 方法重绘界面,必然会十分耗费GPU资源。
- 传统动画所支持的动画类型少,仅有旋转、缩放、位移、透明度这四种动画效果。虽然通过组合可以实现丰富的效果,但相比直接通过改变属性来实现的属性动画来说,还是有很大的局限性的。
因此,Google 为我们提供了一套全新的属性动画框架,来让我们实现更丰富的动画效果。
ObjectAnimator
ObjectAnimator 是属性动画中,最简单也最常用的一个对象。
实现 Animation 框架的功能
平移
前文提到的使 ImageVIew 向右平移 200 像素的动画效果,使用属性动画只需要很简单的几句代码即可实现:
ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F) .setDuration(1000) .start();
我们来分析一下这一句代码。我们调用了ofFloat代码,并传入三个参数。
第一个参数是动画需要操纵的目标,在这里是我们的 ImageView。
第二个参数是所需要操纵的目标所具备的属性名称。
第三个参数是这个动画变化的取值范围。
最后设置一下它的动画的属性,便可以 start 了。
这次我们再次点击 ImageView 目前的位置,成功地弹出了 Toast。这证实了属性动画是通过改变物体的属性来达到动画效果的理论。
当我们需要改变 y 坐标时,只需要把 "translationX" 变为 "translationY" 即可。
其实 ,只要Google对一个对象的某个属性提供了get和set方法,我们就可以使用这个属性来实现动画效果。
其实我们还能用 X Y 两个属性实现之前的动画效果,那么对象属性中 X 的 Y 与 translationX translationY 有什么区别呢?
translationX translationY指的是物体的偏移量,而X Y则表示它最终到达的绝对位置。
旋转
旋转属性使用的是 "rotation" 属性,后面的变换范围的单位是角度。
比如想让 ImageView 旋转90度,只需要
ObjectAnimator.ofFloat(mIvPicture,"rotation",0F,90F) .setDuration(1000) .start();
其他
其实属性动画能操纵的属性,只要具有 set、get 方法,都可以进行操纵。如 scaleX、scaleY 等等...
插值器
Android 为我们内置了插值器,使我们的动画更为自然。比如可以让我们的平移动画像物体的重力加速度由快到慢的 Accelerate 等等
Android中内置了七种插值器,分别是
- Accelerate
- Decelerate
- Accelerate/Decelerate
- Anticipate
- Overshoot
- Anticipate/Overshoot
- Bounce
要应用插值器,可以调用 ObjectAnimator 的 setInterpolator 方法, new 出对应的插值器作为参数(xxxInterpolator)。比如下面这段代码:
animator.setInterpolator(new AccelerateInterpolator());
通过插值器,我们可以让动画的效果更佳自然。
多种属性动画同时作用
当我们把几种动画按顺序写下时,运行程序,会发现效果是三种属性动画的叠加。由此可以发现,属性动画在调用 start 方法后,实际上是一个异步的过程。因此我们就可以看到三个属性动画同时作用的效果。通过这样的方法,其实就可以实现多种属性动画同时作用的效果:
ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F).setDuration(1000).start(); ObjectAnimator.ofFloat(mIvPicture,"rotationX",0F,360F).setDuration(1000).start(); ObjectAnimator.ofFloat(mIvPicture,"translationY",0F,200F).setDuration(1000).start();
其实 Google 为我们提供了更好的方法,来实现这样的效果。
我们可以使用 PropertyValuesHolder 来实现。其构造函数仅仅比 ObjectAnimator 少了一个作用对象参数。之后通过ObjectAnimator 的 ofPropertyValuesHolder 方法,传入作用对象以及要同时作用的 PropertyValuesHolder 即可执行。可以看到下面的代码示例:
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0F,200F); PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("rotationX",0F,360F); PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("translationY",0F,200F); ObjectAnimator.ofPropertyValuesHolder(mIvPicture,p1,p2,p3).setDuration(1000).start();
运行后可以发现,与之前的效果是相同的。
那既然两种方法效果一样,这样相比之前有什么好处么?
- 其实 Google 在 PropertyValuesHolder 内部进行了一些优化,使得我们使用多个属性动画时更加有效率,节省系统资源。
AnimatorSet 属性集合
playTogether 方法
我们其实还可以通过 AnimatorSet,来实现同样的效果。这里我们调用了 set 的 playTogether 方法,使得这些方法同时执行:
AnimatorSet set = new AnimatorSet(); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F); set.playTogether(animator1,animator2,animator3); set.setDuration(1000); set.start();
playSequentially方法
除了 playTogether 方法外,AnimatorSet 还提供了 playSequentially 方法,它可以使得动画按顺序执行。具体顺序取决于调用时的参数顺序。
AnimatorSet set = new AnimatorSet(); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F); set.playSequentially(animator1,animator2,animator3); set.setDuration(1000); set.start();
play 与 with、after 方法
我们除了可以用上述方法来让动画按顺序执行外,也可以通过 AnimatorSet 的 play、with、after、before 等方法相组合来控制动画播放关系。
例如如下的代码就可以实现先平移,再旋转的效果
set.play(animator1).with(animator3); set.play(animator2).after(animator1);
动画监听事件
通过下面的代码,我们可以实现按钮按下后渐隐的效果。
mBtnPress.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ObjectAnimator animator = ObjectAnimator.ofFloat(mBtnPress,"alpha",1F,0F); animator.setDuration(1000); animator.start(); } });
但如果我们想要在动画播放完成后再执行一些操作的话,又该如何实现呢?
- 我们可以使用 ObjectAnimator 的 addListener方法,传入一个AnimatorListener,为动画设置监听事件。
AnimatorListener
一个AnimatorListener,需要实现四个方法,分别是:
- onAnimationStart
- onAnimationEnd
- onAnimationCancel
- onAnimationRepeat
它们的回调时机我们根据字面意思便可以理解。大部分时候,我们需要实现的是onAnimationEnd方法。
animator.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } });
AnimatorListenerAdapter
如果每次监听都需要实现这么多方法,未免太麻烦了一点。因此 Android 为我们提供了另一种方法来添加动画的监听事件:在添加 AnimatorListener 的时候,传入 AnimatorListenerAdapter 即可。这样我们就只需要实现自己需要的方法即可。
animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show(); } });
ValueAnimator
简介
ValueAnimator 本身不作用于任何一个属性,也不提供任何一种动画。它就是一个数值发生器,可以产生想要的各种数值。Android 系统为它提供了很多计算数值的方法,如 int、float 等等。我们也可以自己实现计算数值的方法。其实,在属性动画中,如何产生每一步的动画效果,都是通过 ValueAnimator 计算出来的。
比如我们要实现一个从 0-100 的位移动画。随着动画时间的持续,它产生的值也会从 0-100 递增。通过这个 ValueAnimator 产生的值,再进行属性的设置即可。
那么 ValueAnimator 究竟是如何产生这些值的呢?
- 首先 ValueAnimator会根据会根据动画已进行的时间与它持续的总时间的比值,产生一个0-1的时间因子。有了这样的时间因子,经过相应的变换,就可以根据初始值和最终值来生成中间的相应值。同时,通过插值器的使用,我们还可以进一步控制每一个时间因子产生值的变化速率。如果我们使用的是线性插值器,那么它生成值的时候就会呈一个线性变化。如果我们使用一个加速度插值器,那么它生成值时便会呈一个二次曲线,增长率越来越快。
由于 ValueAnimator 不作用于任何一个属性,也不提供任何一种动画。因此并没有 ObjectAnimator 使用得广泛。
实际上,ObjectAnimator 就是基于 ValueAnimator 进行的一次封装。我们可以查看 ObjectAnimator 的源码,会发现它继承自 ValueAnimator,是它的一个子类。正是 ValueAnimator 产生的变化值,才使得 ObjectAnimator 可以将它应用于各个属性。
使用方法
我们可以通过 ValueAnimator 的 ofXXX 产生一个 XXX 类型的值(如ofInt),然后为 ValueAnimator 添加一个更新的回调事件。在回调事件中,通过参数 animation 的 getAnimationValue() 方法,来获取对应的 value。有了这个值,我们就可以实现我们所有想要的动画效果。
比如此处就通过 ValueAnimator 实现了一个计时器的动画效果。
ValueAnimator animator = ValueAnimator.ofInt(0,100); animator.setDuration(5000); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Integer value = (Integer) animation.getAnimatedValue(); mButton.setText(""+value); } }); animator.start();
自定义数值生成器
前面提到,ValueAnimator 可以创建自定义的数值生成器,做法就是调用 ValueAnimator 的 ofObject 方法,创建一个 TypeEvaluator 作为参数。之后我们可以通过重写 TypeEvaluator 的 evaluate 方法,来按照自己的规则返回具体的值。
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() { @Override public Object evaluate(float fraction, Object startValue, Object endValue) { //计算 return null; //返回值 } });
我们来看一下 evaluate 方法的几个参数
- float fraction:前面提到的时间因子
- Object startValue:起始值
- Object endValue:结束值
通过这三个值,我们就可以经过计算产生所有我们想要的值。
其实,通过 TypeEvaluator,我们不光能产生普通的数据,还能结合泛型,我们还能定义更加复杂的数据:
我们可以在创建 TypeEvaluator 时指定具体类型,来达到更丰富的效果。比如这里就用到了一个名为 PointF 的数据类型:
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() { @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { //计算 return null; //返回值 } });
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
- Android动画系列之属性动画的基本使用教程
- Android属性动画实现图片从左到右逐渐消失
- Android利用属性动画实现优酷菜单
- Android属性动画特点详解
- Android使用属性动画如何自定义倒计时控件详解
- Android属性动画之ValueAnimator代码详解
- Android 属性动画ValueAnimator与插值器详解
- Android源码解析之属性动画详解
- Android深入分析属性动画源码
今天关于css变换与动画详解和css变换与动画详解的区别的介绍到此结束,谢谢您的阅读,有关3D CSS变换,Firefox中的锯齿边、Android Animation动画详解(二): 组合动画特效_html/css_WEB-ITnose、Android 动画详解:属性动画、View 动画和帧动画、Android动画教程之属性动画详解等更多相关知识的信息可以在本站进行查询。
本文标签: