为什么我的我的世界animationapi就.不出来Play函数

为什么我的animation就.不出来Play函数 _ 淄博汽车网
为什么我的animation就.不出来Play函数
/自动播放函数
function autoPlay ()
play = setInterval(function () {
autoPlay();鼠标离开启动自动播放
oBox.onmouseout = function ()
autoPlay()
}.length && (index = 0);/
},3000);= aI
show(index)//&#47
请告诉我吧;W按下时run=true。如果有好方法。多谢;W松开时run=false,这个方法虽然亲测可用;然后在update函数里面判断if(run){播放run动画}else{播放idle动画}新手自学,但是可能不是好方法我自己是使用bool变量进行处理的。声明一个bool变量例如bool run=false
然是用于自身的脚本为什么还要用GameO))
{die&die&).Find.SendMessage或者直接调用Die方法效率不更高.IsPlaying(&quot?直接this!animation?void Die(){
if(.gameobject.Play(&quot
function CrossFadeQueued (animation : string, fadeLength : float = 0.3F, queue : QueueMode = pleteOthers, mode : PlayMode = PlayMode.StopSameLayer) : AnimationState 描述:在前一动画播放完后渐变到下一个动画。例如...
行走动画,我想要在js代码中停止和播放此动画,怎么做...animation.Play(&a2&); // 如果你想动作融合,就...这个函数作用是从当前动画剪辑过度并播放到设定的剪辑...
你说的情况应该只有两种错误 1、检查你的脚本是否是加在按钮上的,可能被你加在帧上了 2、脚本错误,play()要加在on reselse 里面
//鼠标离开启动自动播放 oBox.onmouseout = function () { autoPlay() }; //自动播放函数 function autoPlay () { play = setInterval(function () { index++; index &= aImg.length && (index = 0); show(index); },3000); } autoPlay();//应用...
首先要看你是想做动画还是编程。现在做Flash的话大概有几个方向:Flash动画、Flash编程、Flash特效。 1、如果你之前了解的是AS2.0的一点知识,建议你现在转AS3.0,毕竟AS3.0出来的时间已经很长了,说实话我09年就开始弄AS3.0了,所以如果刚刚开...
既然是用于自身的脚本为什么还要用GameObject.Find? 直接this.gameobject.SendMessage或者直接调用Die方法效率不更高? void Die() { if(!animation.IsPlaying("die")) { animation.Play("die"); } }
InStr返回一字符串在另一字符串中最先出现的位置。 2表示从第二个字符开始搜索,并不是位置从2算起; "abcdefg"表示在……中搜索; "ef"表示搜索……。 所以在"abcdefg"中搜索"ef","d"在第四个,"ef"的"e"在第五个,"e"当然是第五个。
可以在callback函数里 直接用一个while循环进行重复播放
返回主页:
本文网址:/view-.htmlcss3动画|LOFTER(乐乎) - 让兴趣,更有趣
LOFTER for ipad —— 让兴趣,更有趣
下载移动端
关注最新消息
&nbsp&nbsp被喜欢
&nbsp&nbsp被喜欢
{list posts as post}
{if post.type==1 || post.type == 5}
{if !!post.title}${post.title|escape}{/if}
{if !!post.digest}${post.digest}{/if}
{if post.type==2}
{if post.type == 3}
{if !!post.image}
{if post.type == 4}
{if !!post.image}
{if !!photo.labels && photo.labels.length>0}
{var wrapwidth = photo.ow < 500?photo.ow:500}
{list photo.labels as labs}
{var lbtxtwidth = Math.floor(wrapwidth*(labs.ort==1?labs.x:(100-labs.x))/100)-62}
{if lbtxtwidth>12}
{if !!labs.icon}
{list photos as photo}
{if photo_index==0}{break}{/if}
品牌${make||'-'}
型号${model||'-'}
焦距${focalLength||'-'}
光圈${apertureValue||'-'}
快门速度${exposureTime||'-'}
ISO${isoSpeedRatings||'-'}
曝光补偿${exposureBiasValue||'-'}
镜头${lens||'-'}
{if data.msgRank == 1}{/if}
{if data.askSetting == 1}{/if}
{if defined('posts')&&posts.length>0}
{list posts as post}
{if post_index < 3}
{if post.type == 1 || post.type == 5}
{if !!post.title}${post.title|escape}{/if}
{if !!post.digest}${post.digest}{/if}
{if post.type == 2}
{if post.type == 3}
{if post.type == 4}
{if post.type == 6}
{if drlist.length>0}
更多相似达人:
{list drlist as dr}{if drlist.length === 3 && dr_index === 0}、{/if}{if drlist.length === 3 && dr_index === 1}、{/if}{if drlist.length === 2 && dr_index === 0}、{/if}{/list}
暂无相似达人,
{if defined('posts')&&posts.length>0}
{list posts as post}
{if post.type == 2}
{if post.type == 3}
{if post.type == 4}
{if post.type == 6}
this.p={ currentPage:1,pageNewMode:true,isgooglead3:false,ishotrecompost:false,visitorId:0, first:'',tag:'css3动画',recommType:'new',recommenderRole:0,offset:10,type:0,isUserEditor:0,};程序写累了,就来玩玩酷跑小游戏吧,嘿嘿。
雨松MOMO送你一首歌曲,嘿嘿。
Unity3D研究院之在项目中使用Unity4新Mecanim动画(五十三)
Unity3D研究院之在项目中使用Unity4新Mecanim动画(五十三)
围观96121次
编辑日期: 字体:
Unity4的Mecanim动画很早以前就有体验过,迟迟没有加到项目中有两个原因,今天写这篇博客来记录我在做的过程中遇到的一些问题。
1.以前的代码代码量比较多,修改起来动的地方太多了。
2.使用Mecanim动画,还得需要美术的动画做配合才行。
在3.x中播放动画的时候使用Play()或CrossFade(),直接播放动画 或淡入淡出播放动画。
animation.Play("name"); animation.CrossFade("name");
也可以使用队列播放,让动画形成一个队列。
animation.PlayQueued("name"); animation.CrossFade("name1");
我举一个我现在项目的例子。主角攻击敌人是一套连招,连招一共分为4套动画。也就是当玩家连续按下4次攻击键时这四套动画是连续播放的,假如玩家只连续按下2次攻击,可能只会播放前两套动画。代码中你需要判断其中某个动画是否播放完毕,只有播放完毕才能继续播放下一个动画。
if(animation.isPlaying)
if(animation.IsPlaying("attack1"))
大家在仔细想想这个命题,我们可以把动画分成4中可能的队列,也只可能分为这几种队列。
站立动画- 》攻击动画0 -》站立动画
站立动画- 》攻击动画0 -》攻击动画1 -》站立动画
站立动画- 》攻击动画0 -》攻击动画1 -》攻击动画2-》站立动画
站立动画- 》攻击动画0 -》攻击动画1 -》攻击动画2-》攻击动画3-》站立动画
此时如果用unity3以前的动画方式,无非就是上面这几种方法加上一些逻辑判断完成。现在Unity4加入了Mecanim动画,可以很好的帮我们解决这个问题。详细的动画使用教程我就不多说了,网上已经有很多人写过了。
如下图所示,以前我们在使用模型的时候。一个原始模型,原始模型中没有动画。然后是动画模型,每一个动画都会依赖原始模型。动画的名称末尾用 名称 + @name来表示。 这样的做法使用起来非常方便,但是由于每一个动画都会依赖原始模型所以文件会非常大。
Unity4已经将默认模型与动态导入的类型做了修改,你会发现你的模型拖拽入Hierarchy视图中没有Animation组件而是Animator组件。如果你还是想在Unity4中使用以前的动画系统。你需要把每个模型和动画的类型改成 Rig-& Animation Type -& Legacy,如下图所示。
手动的改起来会非常的累。建议你将下面这条脚本放在项目Editor文件夹下(没有创建一个)。这样当你将模型或动画拖入Project视图中,程序会自动帮你修改它的类型,显然Unity已经不建议大家继续使用以前的动画系统了。
12345678910
using UnityEditor;&public class MyEditor : AssetPostprocessor{&&&&public void OnPreprocessModel()&&&&{&&&&&&&&ModelImporter modelImporter = (ModelImporter) assetImporter;&&&&&&&&
modelImporter.animationType = ModelImporterAnimationType.Legacy;&&&&}&& }
下面开始说说新的动画。在Animations选项卡中先勾掉Import Animation 点击Apply。如下图所示,在Rig选项卡中修改Animation Type的类型为Humanoid。 如果你希望现在选择的这个模型做为标准模型的话,在Avatar Definition中选择Create From This Model。点击下方的Configure可以预览你的骨骼。
让美术修改一下以前的动画,将动画中的原始模型去掉,这样还可以减少文件的大小。然后在Porject视图中找一个原始模型拖拽入右侧Preview中,可以看到这个模型已经播放奔跑动画。
此时换一个模型拖入同样可以预览奔跑效果。
如下图所示,在动画的.fbx中 因为动画需要用刚刚生成的骨骼。所以这里Avatar Definition中你需要选择Copy From Other Avatar 。在Source中选择刚刚生成的Avatar 以后所有动画都需要这样来设置。。
下面我们来让这个女模型和男模型共用男模型的那一套动画,在游戏视图中播放。在Project视图中选择Crate-&AnimatorController。然后把Project中男模型和女模型都拖拽入Hierarchy视图中。 将刚刚创建的AnimatorController放置在Controller处。
此时在Unity导航菜单栏中选择Window -》 Animator。 将动画文件拖入Animator窗口中,你会发现两个模型都开始发生运动。如下图所示,黄颜色表示它为原始动画,也就是根动画。用箭头将它们一一前后相连,箭头实际上就是动画播放的条件。请注意看图中两个蓝色的箭头,A播放完后将会播放B动画,可是B却对应了两个箭头,也就是说B播放完后可以播放C也可以回过头来播放A。
那么B播放完到底是播放C还是播放A呢?用鼠标点击一下箭头,看看这这两个箭头的条件吧。分别点开BA 和BC的两个箭头,在右侧监测面板视图中你都会发现Conditions下有一个Exit Time的条件。根据动画的不同对应数值也会不同,我的数值是0.94。也就是当B动画播放0.94s后将播放下一个动画。默认BA和BC的动画时间是一样的,Unity会有限选择下一个动画,也就是A -》 B-》-》C-》D-》A这样循环播放下去。假设我现在需要动画是 A-》B-》A这样循环播放,只需要修改一下BA箭头的条件,将Exit Time改小一点只要比BC箭头上的小就可以。。 其它的播放虚列原理类似。。
接着还有问题了,用时间来做动画切换的条件是不是有点太限制了。Animator还支持自定义条件,在Animator窗口的左下角处,点击“+”按钮就可以添加变量。这里我添加三组变量, float 、int、bool。
变量添加完毕后,继续点击箭头的条件,箭头上可以有一个条件 或者多个条件。如果是多个条件需要多个条件同时满足才可以。 Conditons左键是变量名称,中间是变量条件,右边是变量值。
Greater 表示左边变量大于右边时触发
Less 表示左边变量小于右边时触发
Equals 表示左边变量等于右边时触发
NotEquals表示左边变量不等于右边时触发。
int 变量上述四种都有,float变量只有Greater 和Less, bool变量只有true和false。
此时我们在加深一下理解。选择AB的箭头,也就设置A动画切换B动画的条件。
5 表示 当ft的值大于5的时候触发。
3 表示 当 it的值小于3的时候触发。
表示 当ib的值等于true的时候触发。
只有上述三种条件全部达成时将A动画将切换播放B动画。否则将一直停留在播放A动画处。
那么ft it ib的这三个变量到底在那里设置呢?如下图所示,才记得前面我们创建的三个变量吗? 这三个变量对应的值就是右边的 0.0 0 false 。在编辑器中你可以通过修改这三个数值来满足播放动画的条件。可是在代码中怎么办呢?
在代码中你可以这样来设置或变更它们的条件。 如果说你需要在程序中判断当前动画的一些信息,可以使用 GetCurrentAnimatorStateInfo(0),我查了一下Animator不能直接拿到当前播放动画的名称, 只能拿到它对应的Has值,也就是说你需要将原始的动画名称转换成Hash来判断。
1234567891011121314151617181920212223242526272829303132333435363738
using UnityEngine;using System.Collections;&public class NewBehaviourScript : MonoBehaviour {& private Animator animator ; void&&Start() {
//得到Animator对象
animator = GetComponent&Animator&(); }& void OnGUI() {
if(GUILayout.Button("play",GUILayout.Width(50)))
&&&&//在这里设置变量的条件
animator.SetFloat("ft",6f);
animator.SetInteger("it",2);
&&&&animator.SetBool("ib",true);&
} }& void Update() {
AnimatorStateInfo animatorState = animator.GetCurrentAnimatorStateInfo(0);&
if(animatorState.IsName("Base Layer.Run_FastStop_Idle"))
Debug.Log("动画相等");
Debug.Log("动画不等");
另外Mecanim还支持多个动画的混合。目前Mecanim还有一个最大的难题,也是文章最上面我说的需要美术配合的那部分。之前我们看到的动画都是应用于人型模型,也就是说它支持人形的骨骼, 举个例子我们的项目人和武器是两个骨骼,这样在用Mecanim就悲剧了。因为不同模型武器的骨骼不一样所以公用模型的话会出现武器位置不对的情况。最后我想到的办法就是美术将以前做的武器骨骼重新导出,每个人对应一套自己武器骨骼(或者一些特殊的骨骼)最后生成武器的动画 ,比如 站立动画、攻击动画、死亡动画等。当Mecanim播放动画的时候,同时在播放该模型对应的武器动画,我想这样就可以解决这个问题吧。。
最后欢迎大家一起讨论。。
今天有朋友QQ上问了我已下,是不是非人形动画还得使用老的动画系统?如下图所示,当你把模型导入Unity的时候,这里可以选择它的类型。
legacy:是老的动画系统,这里就多说了。
Generic:是新的动画系统,它就是支持非人形的动画,建议使用它。但是它不能向Humanoid重定向动画。
Humanoid:就是新的人形重定向动画系统。
本文固定链接:
转载请注明:
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
您可能还会对这些文章感兴趣!
Pingback 引用通告:
Pingback 引用通告:
Pingback 引用通告:
Pingback 引用通告:
Pingback 引用通告:
Pingback 引用通告:
Pingback 引用通告:联合动画的代码实现
上几篇给大家分别讲了 ValueAnimator 和 ObjectAnimator,相比而言 ObjectAnimator 更为方便而且由于 set 函数是在控件类内部实现,所以封装性更好。而且在现实使用中一般而言都是使用 ObjectAnimator 的机率比较大。
但 ValueAnimator 和 ObjectAnimator 都只能单单实现一个动画,那如果我们想要使用一个组合动画,比如边放大,边移动,边改变 alpha 值,要怎么办。对于这种组合型的动画,谷歌给我们提供了一个类 AnimatorS这篇我们就着重来看看组合动画的实现方法吧。
一、AnimatorSet——playSequentially,playTogether&
首先,AnimatorSet 针对 ValueAnimator 和 ObjectAnimator 都是适用的,但一般而言,我们不会用到 ValueAnimator 的组合动画,所以我们这篇仅讲解 ObjectAnimator 下的组合动画实现。
在 AnimatorSet 中直接给为我们提供了两个方法 playSequentially 和 playTogether,playSequentially 表示所有动画依次播放,playTogether 表示所有动画一起开始。
1、playSequentially
我们先来看看 playSequentially 的声明:
public void playSequentially(Animator... items);
public void playSequentially(List&Animator& items);
这里有两种声明,第一个是我们最常用的,它的参数是可变长参数,也就是说我们可以传进去任意多个 Animator 对象。这些对象的动画会逐个播放。第二个构造函数,是传进去一个 List& Animator&的列表。原理一样,也是逐个去取 List 中的动画对象,然后逐个播放。但使用起来稍微麻烦一些。
下面我们就举例来看一下 playSequentially 的使用方法,先来看下效果:
从效果图中可以看到,首先改变了 textview1 的颜色,结束后移动 textview1,在移动结束后,开始移动黄色的所以这就是 playSequentially 的效果,即逐个播放动画,一个动画结束后,播放下一个动画
下面我们来看实现代码:
(1)、main.xml 布局
从效果图中也可以看出布局非常简单,就三个控件。代码如下:
&?xml version=&1.0& encoding=&utf-8&?&
&RelativeLayout xmlns:android=&&
android:orientation=&vertical&
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&&
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:padding="10dp"
android:text="start anim"
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="30dp"
android:layout_centerVertical="true"
android:background="#ff00ff"
android:padding="10dp"
android:text="textview1"
android:id="@+id/tv_2"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:padding="10dp"
android:background="#ffff00"
android:text="Hello qijian"/&
这里也没有什么需要注意的地方,下面我们就直接来看 MyActivity 的代码:
**(2)、MyActivity.java**
public class MyActivity extends Activity {
private Button mB
private TextView mTv1, mTv2;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mButton = (Button) findViewById(R.id.btn);
mTv1 = (TextView) findViewById(R.id.tv_1);
mTv2 = (TextView) findViewById(R.id.tv_2);
mButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
doPlaySequentiallyAnimator();
这段代码也没什么难度,首先是初始化 textview1,textview2 和 btn 的对象,然后当点击按钮时执行 doPlaySequentiallyAnimator();函数。下面我们来看看 doPlaySequentiallyAnimator()的具体实现:
private void doPlaySequentiallyAnimator(){
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, &BackgroundColor&,
0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, &translationY&, 0, 300, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, &translationY&, 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
animatorSet.setDuration(1000);
animatorSet.start();
这里首先构造了三个动画,针对 textview1 的是前两个 tv1BgAnimator 和 tv1TranslateY:分别是改变当前动画背景和改变控件 Y 坐标位置;针对 textview2 则只是通过 translationY 来改变控件 Y 坐标位置。有关动画的创建方式,我这里就不再讲了,不理解的同学请参考上篇《Animation 动画详解(七)——ObjectAnimator 基本使用》
然后是利用 AnimatorSet 的 playSequentially 函数将这三个动画组装起来,逐个播放。代码比较简单,就不再细讲。这篇我们就会在这个 demo 的基础上来讲解本篇所有的知识点。
**源码在文章底部给出**
## 2、playTogether
playTogether 表示将所有动画一起播放
我们先来看看 playTogether 的声明:
public void playTogether(Animator... items);
public void playTogether(Collection items);
同样这里也是有两个构造函数,他们两个的意义是一样的,只是传入的参数不一样,第一个依然是传可变长参数列表,第二个则是需要传一个组装好的 Collection&Animator&对象。
下面我们在上面例子的基础上,看看 playTogether 函数的用法;
先来看看效果图:
![](images/94.gif)
从效果图中可以看到,所有动画是一起开始播放的,下面来看看代码:
当点击控钮时,执行以下代码:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, &BackgroundColor&,
0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, &translationY&, 0, 400, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, &translationY&, 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
animatorSet.setDuration(1000);
animatorSet.start();
同样是上面的那三个动画,只是将 playSequentially 改为了 playTogether;
**源码在文章底部给出**
## 3、playSequentially,playTogether 真正意义
想必大家都看到赛马,在赛马开始前,每个马都会被放在起点的小门后面,到点了,门打开,马开始一起往前跑。而假如我们把每匹马看做是一个动画,那我们的 playTogether 就相当于赛马场里每个赛道上门的意义(当比赛开始时,每个赛道上的门会打开,马就可以开始比赛了);也就是说,playTogether 只是一个时间点上的一起开始,对于开始后,各个动画怎么操作就是他们自己的事了,至于各个动画结不结束也是他们自已的事了。所以最恰当的描述就是门只负责打开,打开之后马咋跑,门也管不着,最后,马回不回来跟门也没啥关系。门的责任只是到点就打开而已。放在动画上,就是在激活动画之后,动画开始后的操作只是动画自己来负责。至于动画结不结束,也只有动画自己知道。
而 playSequentially 的意义就是当一匹马回来以后,再放另一匹。那如果上匹马永远没回来,那下一匹马也永远不会被放出来。
放到动画上,就是把激活一个动画之后,动画之后的操作就是动画自己来负责了,这个动画结束之后,再激活下一个动画。如果上一个动画没有结束,那下一个动画就永远也不会被激活。
我们首先用 playTogether 来看个例子:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, &BackgroundColor&,
0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, &translationY&, 0, 400, 0);
tv1TranslateY.setStartDelay(2000);
tv1TranslateY.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, &translationY&, 0, 400, 0);
tv2TranslateY.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
animatorSet.setDuration(2000);
animatorSet.start();
在这个例子中,我们将 tv1TranslateY 开始延迟 2000 毫秒开始,并设为无限循环。tv2TranslateY 设为开始延迟 2000 毫秒。而 tv1BgAnimator 则是没有任何设置,所以是默认直接开始。我们来看效果图:
![](images/95.gif)
在效果图中可以看到,在点击按钮以后,先进行的是 tv1 的颜色变化,在颜色变化完以后,tv2 的延时也刚好结束,此时两个 textview 开始位移变换。最后 textview1 的位移变换是无限循环的。
所以从这个例子中也可以看到,playTogether 只是负责在同一时间点把门拉开,拉开门以后,马跑不跑,那是它自己的事了,回不回来,门也管不着。
playSequentially 也是一样,只是一个回来结束以后,才打开另一个的门。如果上一个一直没回来,那下一个也是永远不会开始的。
& 通过这个例子,我想告诉大家:playTogether 和 playSequentially 在开始动画时,只是把每个控件的动画激活,至于每个控件自身的动画是否具有延时、是否无限循环,只与控件自身的动画设定有关,与 playTogether、playSequentially 无关。playTogether 和 playSequentially 只负责到点激活动画。
我们再来看一个例子:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, &BackgroundColor&,
0xffff00ff, 0xffffff00, 0xffff00ff);
tv1BgAnimator.setStartDelay(2000);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, &translationY&, 0, 300, 0);
tv1TranslateY.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, &translationY&, 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
animatorSet.setDuration(2000);
animatorSet.start();
同样是那三个动画,首先 tv1BgAnimator 设置了延时开始,tv1TranslateY 设置为无限循环;使用 playSequentially 来逐个播放这三个动画,首先是 tv1BgAnimator:在开始之后,这个动画会延时 2000 毫秒再开始。结束之后,激活 tv1TranslateY,这个动画会无限循环。无限循环也就是说它永远也不会结束。那么第三个动画 tv2TranslateY 也永远不会开始。下面来看看效果图:
![](images/96.gif)
在效果图中也可以看出,textview1 先是等了一段时间然后开始背景色变化,然后开始无限循环的上下运动。另一个 textview 永远也不会开始动画了。
**源码在文章底部给出**
& 通过上面两个例子,总结的时候到了:
& - 第一:playTogether 和 playSequentially 在激活动画后,控件的动画情况与它们无关,他们只负责定时激活控件动画。
& - 第二:playSequentially 只有上一个控件做完动画以后,才会激活下一个控件的动画,如果上一控件的动画是无限循环,那下一个控件就别再指望能做动画了。
**4、如何实现无限循环动画**
很多同学会一直纠结如何实现无限循环的组合动画,因为 AnimatorSet 中没有设置循环次数的函数!通过上面的讲解,我们也能知道是否无限循环主要是看动画本身,与门(playTogether)无关!
下面我们就实现三个动画同时开始并无限循环的动画:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, &BackgroundColor&,
0xffff00ff, 0xffffff00, 0xffff00ff);
tv1BgAnimator.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, &translationY&, 0, 400, 0);
tv1TranslateY.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, &translationY&, 0, 400, 0);
tv2TranslateY.setRepeatCount(ValueAnimator.INFINITE);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
animatorSet.setDuration(2000);
animatorSet.start();
上面的代码很容易理解,我们为每个动画设置了无限循环,所以在 playTogether 指定开始动画之后,每个动画都是无限循环的。
效果图如下:
![](images/97.gif)
& 总之:playTogether 和 playSequentially 只是负责指定什么时候开始动画,不干涉动画自己的运行过程。换言之:playTogether 和 playSequentially 只是赛马场上的每个赛道的门,门打开以后,赛道上的那匹马怎么跑跟它没什么关系。
**源码在文章底部给出**
## 二、自由设置动画顺序——AnimatorSet.Builder
### 1、概述
上面我们讲了 playTogether 和 playSequentially,分别能实现一起开始动画和逐个开始动画。但并不是非常自由的组合动画,比如我们有三个动画 A,B,C 我们想先播放 C 然后同时播放 A 和 B。利用 playTogether 和 playSequentially 是没办法实现的,所以为了更方便的组合动画,谷歌的开发人员另外给我们提供一个类 AnimatorSet.B
我们这里使用 AnimatorSet.Builder 实现下面这个效果:
即两个控件一同开始动画
![](images/98.gif)
我们直接来看实现的代码:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, &BackgroundColor&,
0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, &translationY&, 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
AnimatorSet.Builder builder = animatorSet.play(tv1BgAnimator);
builder.with(tv1TranslateY);
animatorSet.start();
关键部分在最后几句:
AnimatorSet animatorSet = new AnimatorSet();
AnimatorSet.Builder builder = animatorSet.play(tv1BgAnimator);
builder.with(tv1TranslateY);
首先是构造一个 AnimatorSet 对象。然后调用 animatorSet.play(tv1BgAnimator)方法生成一个 AnimatorSet.Builder 对象,直接调用 builder.with()就能实现两个控件同时做动画了,多么神奇,下面我们来看看这个 AnimatorSet.Builder 的定义!
**源码在文章底部给出**
### 2、AnimatorSet.Builder 函数
从上面的代码中,我们可以看到 AnimatorSet.Builder 是通过 animatorSet.play(tv1BgAnimator)生成的,这是生成 AnimatorSet.Builder 对象的唯一途径!
//调用 AnimatorSet 中的 play 方法是获取 AnimatorSet.Builder 对象的唯一途径
//表示要播放哪个动画
public Builder play(Animator anim)
在上面的例子中,我们已经接触 AnimatorSet.Builder 的 with(Animator anim)函数,其实除了 with 函数以外,AnimatorSet.Builder 还有一些函数,声明如下:
//和前面动画一起执行
public Builder with(Animator anim)
//执行前面动画前执行动画
public Builder before(Animator anim)
//执行前面的动画后执行该动画
public Builder after(Animator anim)
//延迟 n 毫秒之后执行动画
public Builder after(long delay)
上面每个函数的意义很好理解,这里要格外注意一点,他们每个函数的返回值都是 Builder 对象,也就是说我们有两种方式使用他们:
**方式一:使用 builder 对象逐个添加动画**
AnimatorSet.Builder builder = animatorSet.play(tv1TranslateY);
builder.with(tv2TranslateY);
builder.after(tv1BgAnimator);
**方式二:串行方式**
由于每个函数的返回值都是 Builder 对象,所以我们是依然可以直接调用 Builder 的所有函数的,所以就可以用串行的方式把他们一行串起来,所以上面的代码我们也可以写成下面的简化方式:
animatorSet.play(tv1TranslateY).with(tv2TranslateY).after(tv1BgAnimator);
下面我们就举个例子来看一下他们的用法,这里实现的效果是:在 tv1 颜色变化后,两个控件一同开始位移动画:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, &BackgroundColor&,
0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, &translationY&, 0, 400, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, &translationY&, 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv1TranslateY).with(tv2TranslateY).after(tv1BgAnimator);
animatorSet.setDuration(2000);
animatorSet.start();
上面的代码比较简单,就不再讲了,看下效果图:
![](images/99.gif)
**源码在文章底部给出**
## 三、AnimatorSet 监听器
在 AnimatorSet 中也可以添加监听器,对应的监听器为:
public static interface AnimatorListener {
当 AnimatorSet 开始时调用
void onAnimationStart(Animator animation);
当 AnimatorSet 结束时调用
void onAnimationEnd(Animator animation);
当 AnimatorSet 被取消时调用
void onAnimationCancel(Animator animation);
当 AnimatorSet 重复时调用,由于 AnimatorSet 没有设置 repeat 的函数,所以这个方法永远不会被调用
void onAnimationRepeat(Animator animation);
添加方法为:
public void addListener(AnimatorListener listener);
好像这个 listenner 和 ValueAnimator 的一模一样啊。不错,确实是一模一样,因为 ValueAnimator 和 AnimatorSet 都派生自 Animator 类,而 AnimatorListener 是 Animator 类中的函数。
监听器的用法并不难,难点在于,我们 AnimatorSet 中的监听器,监听的 AnimatorSet 本身的动作,还是它内部的每个动画的动作?在 AnimatorSet 代码注释中我们已经提到,它监听的是 AnimatorSet 的过程,所以只有当 AnimatorSet 的状态发生变化时,才会被调用。
我们来看个例子:
额外添加一个 Cancel 按钮,在点击 start 按钮时,开始动画,在点击取消按钮时取消动画
private AnimatorSet mAnimatorS
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mButton = (Button) findViewById(R.id.btn);
mBtnCancel = (Button) findViewById(R.id.btn_cancel);
mTv1 = (TextView) findViewById(R.id.tv_1);
mTv2 = (TextView) findViewById(R.id.tv_2);
mButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mAnimatorSet = doListenerAnimation();
mBtnCancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (null != mAnimatorSet) {
mAnimatorSet.cancel();
这段代码很简单,在点击开始时,执行 doListenerAnimation()函数, doListenerAnimation()会把构造的 AnimatorSet 对象返回,在点击取消时,取消 AnimatorS
然后看一下 doListenerAnimation()的代码:
private AnimatorSet doListenerAnimation() {
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
tv2TranslateY.setRepeatCount(ValueAnimator.INFINITE);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv1TranslateY).with(tv2TranslateY).after(tv1BgAnimator);
//添加 listener
animatorSet.addListener(new Animator.AnimatorListener() {
public void onAnimationStart(Animator animation) {
Log.d(tag, "animator start");
public void onAnimationEnd(Animator animation) {
Log.d(tag, "animator end");
public void onAnimationCancel(Animator animation) {
Log.d(tag, "animator cancel");
public void onAnimationRepeat(Animator animation) {
Log.d(tag, "animator repeat");
animatorSet.setDuration(2000);
animatorSet.start();
return animatorS
这里着重注意两点:
第一:将动画 tv2TranslateY 设置为无限循环
第二:在 animatorSet 添加的 Animator.AnimatorListener()中每个部分添加上 log
我们看一下对应的动画及 Log
对应的 Log
从效果图和对应中的 Log 中也可以看到,虽然我们的 tv2TranslateY 动画在无限循环,但 Log 中没有打印出对应的 repeat 的日志,从日志中也可以看出,AnimatorSet 的监听函数也只是用来监听 AnimatorSet 的状态的,与其中的动画无关;
所以我们来总结一下 AnimatorSet 的监听:
1、AnimatorSet 的监听函数也只是用来监听 AnimatorSet 的状态的,与其中的动画无关;
2、AnimatorSet 中没有设置循环的函数,所以 AnimatorSet 监听器中永远无法运行到 onAnimationRepeat()中!
有关如何实现无限循环的问题,我们上面已经讲了,就不再赘述
源码在文章底部给出
四、通用函数逐个设置与 AnimatorSet 设置的区别
1、概述及简单示例
在 AnimatorSet 中还有几个函数:
//设置单次动画时长
public AnimatorSet setDuration(long duration);
//设置加速器
public void setInterpolator(TimeInterpolator interpolator)
//设置 ObjectAnimator 动画目标控件
public void setTarget(Object target)
这几个函数好像比较诡异,因为在 ObjectAnimator 中也都有这几个函数。那在 AnimatorSet 中设置与在单个 ObjectAnimator 中设置有什么区别呢?
区别就是:在 AnimatorSet 中设置以后,会覆盖单个 ObjectAnimator 中的设置;即如果 AnimatorSet 中没有设置,那么就以 ObjectAnimator 中的设置为准。如果 AnimatorSet 中设置以后,ObjectAnimator 中的设置就会无效。
下面我们简单举个例子来看下
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
tv1TranslateY.setDuration();
tv1TranslateY.setInterpolator(new BounceInterpolator());
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
tv2TranslateY.setInterpolator(new AccelerateDecelerateInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv2TranslateY).with(tv1TranslateY);
animatorSet.setDuration(2000);
animatorSet.start();
在第这个例子中,我们通过 animatorSet.setDuration(2000);设置为所有动画单词运动时长为 2000 毫秒,虽然我们给 tv1TranslateY 设置了单次动画时长为 tv1TranslateY.setDuration();但由于 AnimatorSet 设置了 setDuration(2000)这个参数以后,单个动画的时长设置将无效。所以每个动画的时长为 2000 毫秒。
但我们这里还分别给 tv1 和 tv2 设置了加速器,但并没有给 AnimatorSet 设置加速器,那么 tv1,tv2 将按各自加速器的表现形式做动画。
同样,如果我们给 AnimatorSet 设置上了加速器,那么单个动画中所设置的加速器都将无效,以 AnimatorSet 中的加速器为准。
效果图如下:
从动画中也可以看到,这两个控件同时开始,同时结束,这说明他们两个的单次动画的时长是一样的。也就是以 animatorSet.setDuration(2000)为准的 2000 毫秒。
其次,这两个动画在运动过程中的表现形式是完全不一样的,这说明他们的加速器是不一样的。也就是在 AnimatorSet 没有统一设置的情况下,各自按各自的来。
2、setTarget(Object target)示例
//设置 ObjectAnimator 动画目标控件
public void setTarget(Object target)
这里我们着重讲一下 AnimatorSet 的 setTartget 函数,这个函数是用来设置目标控件的,也就是说,只要通过 AnimatorSet 的 setTartget 函数设置了目标控件,那么单个动画中的目标控件都以 AnimatorSet 设置的为准
我们来看个例子:
ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(mTv1, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(tv1BgAnimator,tv2TranslateY);
animatorSet.setDuration(2000);
animatorSet.setTarget(mTv2);
animatorSet.start();
在这段代码中,我们给 tv1 设置了改变背景色,给 tv2 设置了上下移动。但由于我们通过 animatorSet.setTarget(mTv2);将各个动画的目标控件设置为 mTv2,所以 tv1 将不会有任何动画,所有的动画都会发生在 tv2 上。
效果图如下:
所以 AnimatorSet.setTarget()的作用就是将动画的目标统一设置为当前控件,AnimatorSet 中的所有动画都将作用在所设置的 target 控件上
源码在文章底部给出
五、AnimatorSet 之 setStartDelay(long startDelay)
//设置延时开始动画时长
public void setStartDelay(long startDelay)
上面我们讲了,当 AnimatorSet 所拥有的函数与单个动画所拥有的函数冲突时,就以 AnimatorSet 设置为准。但唯一的例外就是 setStartDelay。
setStartDelay 函数不会覆盖单个动画的延时,而且仅针对性的延长 AnimatorSet 的激活时间,单个动画的所设置的 setStartDelay 仍对单个动画起作用。
我们来看下面的一个例子:
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
tv2TranslateY.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv1TranslateY).with(tv2TranslateY);
animatorSet.setStartDelay(2000);
animatorSet.setDuration(2000);
animatorSet.start();
在这个动画中,我们首先给 AnimatorSet 设置了延时,所以 AnimatorSet 会在 2000 毫秒以后,才会执行 start()函数。另外我们还给 tv2 设置了延时 2000 毫秒,所以在动画开始后,tv1 会直接运动,但 tv2 要等 2000 毫秒以后,才会开始运动。
这里要特别提醒大家注意一行代码:
animatorSet.play(tv1TranslateY).with(tv2TranslateY);
在这行代码中,我们 play 的是 tv1!而且 tv1 是没有设置延时的!这里要非常注意一下,下面我们会深入的探讨这个问题。
我们来看看效果图:
在这个效果图中可以看到在点击了 start anim 按钮以后,动画并没有立即开始,这是因为我们给 AnimatorSet 设置了延时;另外在 AnimatorSet 延时过了以后,可以看到 tv1 立刻开始动画,但此时 tv2 并没有任何动静。这是因为我们单独给 tv2 又设置了延时。
所以从这里,我们可以得到一个结论:
AnimatorSet 的延时是仅针对性的延长 AnimatorSet 激活时间的,对单个动画的延时设置没有影响。
上面我们提示大家注意动画顺序,上面的动画顺序是
animatorSet.play(tv1TranslateY).with(tv2TranslateY);
我们这里将动画顺序翻倒一下,看会是什么结果呢?
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
tv2TranslateY.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv2TranslateY).with(tv1TranslateY);
animatorSet.setStartDelay(2000);
animatorSet.setDuration(2000);
animatorSet.start();
我们先来看一下动画效果:
这个动画效果有没有感觉非常奇怪,这里的代码仅仅调换了 play 的顺序,却与上面的效果完全不一样!
按说这里的效果应该与上个的效果是一样的才对,即在 AnimatorSet 被激活以后,tv1 应该立即运行,等 2000 毫秒后 tv2 才开始运行。
但这里的效果却是过了一段时间以后,tv1 和 tv2 一起运行!
这是因为:
AnimatorSet 真正激活延时 = AnimatorSet.startDelay+第一个动画.startDelay
也就是说 AnimatorSet 被激活的真正延时等于它本身设置的 setStartDelay(2000)延时再上第一个动画的延时;
在真正的延时过了之后,动画被激活,这时相当于赛马场的每个跑道的门就打开了。每个动画就按照自己的动画处理来操作了,如果有延时就延时动画。但由于第一个动画的延时已经 AnimatorSet 被用掉了,所以第一个动画就直接运行。
在这个例子中,由于只有 tv1 有延时,而在 AnimatorSet 被激活后,tv1 的延时被 AnimatorSet 用掉了,所以 tv1 直接运行;而在 AnimatorSet 激活后,由于 tv2 没有设置延时,所以 tv2 直接运动。
下面我们再举个例子,同样是上面的代码,我们如果给 tv2 加上延时会怎样:
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
tv1TranslateY.setStartDelay(2000);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
tv2TranslateY.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv2TranslateY).with(tv1TranslateY);
animatorSet.setStartDelay(2000);
animatorSet.setDuration(2000);
animatorSet.start();
代码与上面的一样,只是不仅给 tv2 添加了延时,而且给 tv1 添加了延时。
效果图如下:
从效果图中也可以看到,由于 AnimatorSet 激活延时 = AnimatorSet.startDelay+第一个动画.startDelay;所以在 4000 毫秒后,动画被激活,tv2 由于已经被用掉了延时,所以在激活后直接开始。但 tv1 则按照自己的设定,在动画激活后,延时 2000 毫秒后才开始动画;
经过上面的例子,我们可以得出以下结论:
AnimatorSet 的延时是仅针对性的延长 AnimatorSet 激活时间的,对单个动画的延时设置没有影响。
AnimatorSet 真正激活延时 = AnimatorSet.startDelay+第一个动画.startDelay
在 AnimatorSet 激活之后,第一个动画绝对是会开始运行的,后面的动画则根据自己是否延时自行处理。
源码在文章底部给出
好了,这篇文章把 AnimatorSet 相关的知识都讲完了,看似简单的知识,其实比较复杂。尤其是最后的延时部分,大家可以多看看源码,多试试这些函数的用法,应该就能理解出来。下篇将带大家来看动画的 XML 实现方式。
如果本文有帮到你,记得加关注哦
源码下载地址:
请大家尊重原创者版权,转载请标明出处: 谢谢

我要回帖

更多关于 animation css 的文章

 

随机推荐