这次主要就介绍android动画,android动画目前分为三种形式,Tween Animation 这个只能应用于view对象上面的,Drawable Animation这个是帧动画,就是类似我们有一些列的图片依次播放图片时出现的动画,Property Animation 这个是属性动画,这也是在android3.0之后引进的动画,在手机的版本上是android4.0就可以使用这个动画,下面我们主要就是针对这三种情况进行介绍。
Tween Animation
这个动画在Property Animation之前使用最多的,当然在android4.0之后也是有很多人使用这个动画来弄一些简单的动画效果,Tween Animation主要是包括四种动画实现效果:
- AlphaAniamtion:渐变效果,这个是一个透明度的动画效果
AlphaAnimation(float fromAlpha,float toAlpha)
这个就是AlphaAnimation的构造函数,fromAlpha表示的是动画初始时的透明度,toAlpha表示的是动画结束时的透明度,这个取值范围是0~1,0表示的是完全透明,1表示的是完全不透明
- ScaleAnimation:图片进行放大缩小的动画效果,
ScaleAnimation(float fromX, float toX, float fromY,float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
上面就是这个Scale参数的情况,这个参数是最多的,fromX:起始X坐标上的伸缩尺寸,toX:结束X坐标上的伸缩尺寸,fromY:起始Y坐标上的伸缩尺寸,toY:结束Y坐标上的伸缩尺寸,关于这个伸缩尺寸,0表示的就是看不见,1表示原始大小,依此类推,1.5表示的就是1.5倍
pivotXType和pivotYType分别表示在X和Y轴上伸缩模式。这里有三个值:
Animation.ABSOLUTE:这个表示的是绝对坐标
Animation.RELATIVE_TO_SELF:相对于自己的坐标
Animation.RELATIVE_TO_PARENT:相对于父控件
上面这些说的都是这个动画效果相对于哪一个点来进行变化的,Animation.RELATIVE_TO_SELF这个就相对于自己的坐标,就是说这个坐标原始坐标是在你设置view的左上角,Animation.RELATIVE_TO_PARENT相对于父控件的坐标,这个大多数指的就是手机上的坐标原点。Animation.ABSOLUTE绝对坐标说的就是具体相对哪个一个点,比如(100,200),就是表示相对坐标点在(100,200)这个点来进行动画。
pivotXValue和pivotYValue值就是相对上面的值设置的,表示的是相对于哪一个点来进行放大缩小的动画,对于Animation.RELATIVE_TO_SELF和Animation.RELATIVE_TO_PARENT
(0,0)表示的是原点,(0.5f,0.5f)表示的中间点这个对于Animation.RELATIVE_TO_SELF相对于view控件的中间点,Animation.RELATIVE_TO_PARENT就是值该view上父控件的中间点,(1,1)表示的就是右下角的坐标。这个我们可以多多试试就知道效果了。
一般情况下使用是Animation.RELATIVE_TO_SELF,选择点是(0.5f,0.5f)就是该view的中间点,这样图片变化看起来不会产生很奇怪的感觉。
- TranslateAnimation:view在水平方向和垂直方向进行移动动画效果
TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta)
fromXDelta和fromYDelta分别表示在X和Y轴上面的起始坐标,(0,0)这个表示的就是当前view的坐标,toXDelta和toYDelta分别表示最终目标,如果只是X轴移动或者Y轴移动,那么可以把对应不移动的坐标设置为0。
- RotateAnimation:旋转动画效果
RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue)
fromDegrees和toDegrees分别表示的起始角度和结束角度,比如(0,45)这个就是表示从默认状态旋转到45度的意思。剩下的参数上面已经介绍过来,比如下面的代码:
RotateAnimation rotate=new RotateAnimation(0, 50, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
表示就是从默认状态旋转到50度,旋转的中心点就是这个view的中心点(Animation.RELATIVE_TO_SELF表示的以自身为参考点,0.5f表示就是一般)
上面介绍就是这个Tween Animation动画效果,分别是透明度的变化,放大缩小,移动以及旋转动画效果,这些动画除了上面的构造函数之外当然还有一些公共的其它方法,下面就介绍一下:
setDuration(long durationMillis)
这个表示的是设置动画的显示时间,就是这个动画从初始状态到结束状态所需要的时间,durationMillis参数为动画显示时间的长短,单位是毫秒。
setStartOffset(long startOffset)
这个表示的是动画的开始时间,startOffset表示就是动画的开始时间,单位毫秒(有时候我们在startAnimation之后可能不希望立即取执行这个动画,需要等待一会再进行动画就可以使用这个
setFillAfter(boolean fillAfter)
这个表示的动画结束之后是否保留结束的位置,这个值默认是flase表示动画结束之后不保留动画的位置,就是说在我们进行动画效果结束之后又会自动恢复到原始的状态,true表示就是保留动画结束时的状态,这个值一般都是要设置为true的
startAnimation(Animation animation)
这个是在view对象上使用的,表示开始进行动画,参数就是我们上面说的那四种(注意上面的四种类型都是继承于Animation的),比如我现在有一个ImageView对象image,那么我现在要开始动画时就是用imageView.startAnimation(rotateAnimation);就可以进行动画了,
setInterpolator(Interpolator i)
这个表示的设置动画的变化速度,这里android提供很多类型的Interpolator类型的变化器
1。setInterpolator(new AccelerateInterpolator(float factor):这个AccelerateInterpolator表示的是加速,factor参数可以设置为加速的倍数,数值越大动画的速度越快,当然也可以是默认的new AccelerateInterpolator()默认这个参数为1。我们来看一下源码:
/** * An interpolator where the rate of change starts out slowly and * and then accelerates. * */ public class AccelerateInterpolator implements Interpolator { private final float mFactor; private final double mDoubleFactor; public AccelerateInterpolator() { mFactor = 1.0f; mDoubleFactor = 2.0; } /** * Constructor * * @param factor Degree to which the animation should be eased. Seting * factor to 1.0f produces a y=x^2 parabola. Increasing factor above * 1.0f exaggerates the ease-in effect (i.e., it starts even * slower and ends evens faster) */ public AccelerateInterpolator(float factor) { mFactor = factor; mDoubleFactor = 2 * mFactor; } public AccelerateInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator); mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f); mDoubleFactor = 2 * mFactor; a.recycle(); } public float getInterpolation(float input) { if (mFactor == 1.0f) { return input * input; } else { return (float)Math.pow(input, mDoubleFactor); } } }
上面那个就是AccelerateInterpolator的源码,这个源码中有两个构造函数一个带参数一个不带参数的,从上面代码中getInterpolation这个方法是最重要的,那么跟踪一下这个方法调用是在Animation.java类中的getTransformation()方法
public boolean getTransformation(long currentTime, Transformation outTransformation) { if (mStartTime == -1) { mStartTime = currentTime; } final long startOffset = getStartOffset(); final long duration = mDuration; float normalizedTime; if (duration != 0) { normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) / (float) duration; } else { // time is a step-change with a zero duration normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f; } final boolean expired = normalizedTime >= 1.0f; mMore = !expired; if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) { if (!mStarted) { fireAnimationStart(); mStarted = true; if (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); }
。。。。。。。。。
return mMore; }
上面就是getTransformation()方法,在这个方法中也看到之前设置的getStartOffset()以及mDuration等等,在下面发现这么一句话
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);mInterpolator对象创建也是在这个类里面
public void setInterpolator(Interpolator i) { mInterpolator = i; }
看上面就是我们代码中设置的,那么来看看这个getInterpolation里面参数的值,从上面源码中知道mFillEnabled和mCycleFlip默认值都是flase,一般情况下我们都不会去设置这两个值都是取默认值的,if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);这个设置了normalizedTime的值,就是下面要用做getInterpolation参数值,从上面的代码中可以发现normalizedTime这个值是不小于0的,Math.max(Math.min(normalizedTime, 1.0f), 0.0f)表示取值范围就是0~1,也就是手这个getInterpolation(float input)这个input参数的变化就是在指定的动画事件内从0到1递增变化。
我们来看看Interpolator这个类
package android.view.animation; import android.animation.TimeInterpolator; /** * An interpolator defines the rate of change of an animation. This allows * the basic animation effects (alpha, scale, translate, rotate) to be * accelerated, decelerated, repeated, etc. */ public interface Interpolator extends TimeInterpolator { // A new interface, TimeInterpolator, was introduced for the new android.animation // package. This older Interpolator interface extends TimeInterpolator so that users of // the new Animator-based animations can use either the old Interpolator implementations or // new classes that implement TimeInterpolator directly. }
再看这个TimeInterpolator类
/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.animation; /** * A time interpolator defines the rate of change of an animation. This allows animations * to have non-linear motion, such as acceleration and deceleration. */ public interface TimeInterpolator { /** * Maps a value representing the elapsed fraction of an animation to a value that represents * the interpolated fraction. This interpolated value is then multiplied by the change in * value of an animation to derive the animated value at the current elapsed animation time. * * @param input A value between 0 and 1.0 indicating our current point * in the animation where 0 represents the start and 1.0 represents * the end * @return The interpolation value. This value can be more than 1.0 for * interpolators which overshoot their targets, or less than 0 for * interpolators that undershoot their targets. */ float getInterpolation(float input); }
从这段代码中我们得出结论就是所有的变化器都是继承于Interpolator接口,而且都实现了float getInterpolation(float input);这个方法,那么我们就要弄清楚这个getTransformation()方法在哪里调用,我们说过StartAnimation是view对象调用那么我们在View.java里面
public void startAnimation(Animation animation) { animation.setStartTime(Animation.START_ON_FIRST_FRAME); setAnimation(animation); invalidateParentCaches(); invalidate(true); }
这段代码中最后一句就是更新,看一下
/** * This method is called by ViewGroup.drawChild() to have each child view draw itself. * This draw() method is an implementation detail and is not intended to be overridden or * to be called from anywhere else other than ViewGroup.drawChild(). */ boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated; boolean more = false; final boolean childHasIdentityMatrix = hasIdentityMatrix(); final int flags = parent.mGroupFlags; if ((flags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) == ViewGroup.FLAG_CLEAR_TRANSFORMATION) { parent.getChildTransformation().clear(); parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; } Transformation transformToApply = null; boolean concatMatrix = false; boolean scalingRequired = false; boolean caching; int layerType = getLayerType(); final boolean hardwareAccelerated = canvas.isHardwareAccelerated(); if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 || (flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) { caching = true; // Auto-scaled apps are not hw-accelerated, no need to set scaling flag on DisplayList if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired; } else { caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated; } final Animation a = getAnimation(); if (a != null) { more = drawAnimation(parent, drawingTime, a, scalingRequired); concatMatrix = a.willChangeTransformationMatrix(); if (concatMatrix) { mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; } transformToApply = parent.getChildTransformation(); } else { 。。。。。。。。。。。。。。。。。。。。。。。
上面这段代码中有这么一句话 more = drawAnimation(parent, drawingTime, a, scalingRequired),这个函数就是
private boolean drawAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired) { Transformation invalidationTransform; final int flags = parent.mGroupFlags; final boolean initialized = a.isInitialized(); if (!initialized) { a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); onAnimationStart(); } final Transformation t = parent.getChildTransformation(); boolean more = a.getTransformation(drawingTime, t, 1f);
。。。。。。。。。。。。。。。。。。。。。。。。。
看到上面的drawAnimation方法中就有a.getTransformation(drawingTime, t, 1f);这个方法,我们也就明白了这个getTransformation()方法是在startAnimation()之后调用的。
2。setInterpolator(new AccelerateDecelerateInterpolator()):这个AccelerateDecelerateInterpolator表示的是先加速后减速的动画
/** * An interpolator where the rate of change starts and ends slowly but * accelerates through the middle. * */ public class AccelerateDecelerateInterpolator implements Interpolator { public AccelerateDecelerateInterpolator() { } @SuppressWarnings({"UnusedDeclaration"}) public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } }
3。setInterpolator(new DecelerateInterpolator(float factor)):这个表示的就是减速,factor和上面的加速参数是一个意思,只不过作用是相反的,也可以不带参数new DecelerateInterpolator()这样
/** * An interpolator where the rate of change starts out quickly and * and then decelerates. * */ public class DecelerateInterpolator implements Interpolator { public DecelerateInterpolator() { } /** * Constructor * * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces * an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the * ease-out effect (i.e., it starts even faster and ends evens slower) */ public DecelerateInterpolator(float factor) { mFactor = factor; } public DecelerateInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator); mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f); a.recycle(); } public float getInterpolation(float input) { float result; if (mFactor == 1.0f) { result = (float)(1.0f - (1.0f - input) * (1.0f - input)); } else { result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor)); } return result; } private float mFactor = 1.0f; }
4。setInterpolator(new CycleInterpolator()):动画循环播放特定次数,速率改变沿着正弦曲线
/** * Repeats the animation for a specified number of cycles. The * rate of change follows a sinusoidal pattern. * */ public class CycleInterpolator implements Interpolator { public CycleInterpolator(float cycles) { mCycles = cycles; } public CycleInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator); mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f); a.recycle(); } public float getInterpolation(float input) { return (float)(Math.sin(2 * mCycles * Math.PI * input)); } private float mCycles; }
5。setInterpolator(new LinearInterpolator()):表示匀速
/** * An interpolator where the rate of change is constant * */ public class LinearInterpolator implements Interpolator { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return input; } }
6。setInterpolator(new OvershootInterpolator()) 超越,最后超出目的值然后缓慢改变到目的值
/** * An interpolator where the change flings forward and overshoots the last value * then comes back. */ public class OvershootInterpolator implements Interpolator { private final float mTension; public OvershootInterpolator() { mTension = 2.0f; } /** * @param tension Amount of overshoot. When tension equals 0.0f, there is * no overshoot and the interpolator becomes a simple * deceleration interpolator. */ public OvershootInterpolator(float tension) { mTension = tension; } public OvershootInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.OvershootInterpolator); mTension = a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f); a.recycle(); } public float getInterpolation(float t) { // _o(t) = t * t * ((tension + 1) * t + tension) // o(t) = _o(t - 1) + 1 t -= 1.0f; return t * t * ((mTension + 1) * t + mTension) + 1.0f; } }
7。setInterpolator(new BounceInterpolator()):跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
/** * An interpolator where the change bounces at the end. */ public class BounceInterpolator implements Interpolator { public BounceInterpolator() { } @SuppressWarnings({"UnusedDeclaration"}) public BounceInterpolator(Context context, AttributeSet attrs) { } private static float bounce(float t) { return t * t * 8.0f; } public float getInterpolation(float t) { // _b(t) = t * t * 8 // bs(t) = _b(t) for t < 0.3535 // bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408 // bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644 // bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0 // b(t) = bs(t * 1.1226) t *= 1.1226f; if (t < 0.3535f) return bounce(t); else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f; else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f; else return bounce(t - 1.0435f) + 0.95f; } }
8。setInterpolator(new AnticipateOvershootInterpolator()):反向加超越,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
/** * An interpolator where the change starts backward then flings forward and overshoots * the target value and finally goes back to the final value. */ public class AnticipateOvershootInterpolator implements Interpolator { private final float mTension; public AnticipateOvershootInterpolator() { mTension = 2.0f * 1.5f; } /** * @param tension Amount of anticipation/overshoot. When tension equals 0.0f, * there is no anticipation/overshoot and the interpolator becomes * a simple acceleration/deceleration interpolator. */ public AnticipateOvershootInterpolator(float tension) { mTension = tension * 1.5f; } /** * @param tension Amount of anticipation/overshoot. When tension equals 0.0f, * there is no anticipation/overshoot and the interpolator becomes * a simple acceleration/deceleration interpolator. * @param extraTension Amount by which to multiply the tension. For instance, * to get the same overshoot as an OvershootInterpolator with * a tension of 2.0f, you would use an extraTension of 1.5f. */ public AnticipateOvershootInterpolator(float tension, float extraTension) { mTension = tension * extraTension; } public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator); mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) * a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f); a.recycle(); } private static float a(float t, float s) { return t * t * ((s + 1) * t - s); } private static float o(float t, float s) { return t * t * ((s + 1) * t + s); } public float getInterpolation(float t) { // a(t, s) = t * t * ((s + 1) * t - s) // o(t, s) = t * t * ((s + 1) * t + s) // f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5 // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0 if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension); else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f); } }
9。setInterpolator(new AnticipateInterpolator()):反向 ,先向相反方向改变一段再加速播放
/** * An interpolator where the change starts backward then flings forward. */ public class AnticipateInterpolator implements Interpolator { private final float mTension; public AnticipateInterpolator() { mTension = 2.0f; } /** * @param tension Amount of anticipation. When tension equals 0.0f, there is * no anticipation and the interpolator becomes a simple * acceleration interpolator. */ public AnticipateInterpolator(float tension) { mTension = tension; } public AnticipateInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnticipateInterpolator); mTension = a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f); a.recycle(); } public float getInterpolation(float t) { // a(t) = t * t * ((tension + 1) * t - tension) return t * t * ((mTension + 1) * t - mTension); } }
就上面这么多了,按照上面的代码我们也可以自定义我们符合我们自己的Interpolator,定义方法就是写一个类继承于Interpolator接口,并且去实现getInterpolation()方法,在该方法里面做相应的运算。
常用的方法就上面这些,来看一下一个ScaleAnimation用法,其它类似:
private ScaleAnimation scale(){ ScaleAnimation scaleAnimation=new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(1000); scaleAnimation.setStartOffset(0); scaleAnimation.setInterpolator(new AccelerateInterpolator()); scaleAnimation.setFillAfter(true); return scaleAnimation; }
开启这个动画在一个按钮上面
imageView=(ImageView) findViewById(R.id.image); scaleBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub imageView.startAnimation(scale()); } });
上面这个就实现图片放大缩小的效果
如果我们想要实现两种以上的动画如何处理呢,这个时候我们就可以使用AnimationSet这个类实现多个动画叠加效果,
AnimationSet(boolean shareInterpolator);
这个参数设为false表示可以在每个添加到AnimationSet中的Animation都使用Interpolator,且效果都能清楚的观察。设置为true如果在添加到AnimationSet中的Animation设置Interpolator将无效果,通过设置AnimationSet的Interpolator可以设置所有动画的Interpolator且所有动画的Interpolator都一样。
private AnimationSet allAnimation(){ AnimationSet set=new AnimationSet(boolean shareInterpolator); TranslateAnimation translate=new TranslateAnimation(0, 100, 0, 100); RotateAnimation rotate=new RotateAnimation(0, 50, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); set.addAnimation(translate); set.addAnimation(rotate); set.setInterpolator(new AnticipateOvershootInterpolator()); set.setFillAfter(true); set.setDuration(1000); set.setStartOffset(100); return set; }
我们看到addAnimation就是添加动画效果,其它方法和那个是一样的
我们在使用的过程有时候需要监听动画的开始和结束,AnimationListener这个就是动画监听
set.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } @Override public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } @Override public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub } });
看上面的意思就会明白那个是表示动画的开始,那个是动画结束了
这个我们可以在res/anim目录中通过xml来写动画
xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromAlpha="0" android:toAlpha="1" android:duration="1000" /> <translate android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:fromXDelta="0" android:toXDelta="100" android:fromYDelta="0" android:toYDelta="100" android:startOffset="50" android:duration="1000" /> set>
上面就是xml写的,那么如何加载呢?看下面的代码
Animation an=AnimationUtils.loadAnimation(AnimationTest.this, R.anim.itchqanimator); imageView.startAnimation(an);
这个就是加载xml里面的动画的
Property Animation
这个是属性动画,是android4.0引入手机中(android 3.0中就有了只是3.0主要的在平板电脑上使用的),我们上面讲解的那种tween Animation动画改变的是view绘制,而没有改变View对象本身,比如,你有一个Button,坐标 (100,100),Width:200,Height:50,而你有一个动画使其变为Width:100,Height:100,你会发现动画过程中触 发按钮点击的区域仍是(100,100)-(300,150)。而在Property Animation中,改变的是对象的实际属性,而且Property Animation不止可以应用于View,还可以应用于任何对象。
ValueAnimator类就是这个的包含Property Animation的动画所以核心功能,如动画的时间,开始,结束的属性值等等,当时对于ValueAnimator来说我们一般都不会直接使用这个,我们都是直接使用ValueAnimator的子类就是ObjectAnimator。
ObjectAnimator是继承于ValueAnimator的,使用这个ObjectAnimator是有条件限制的
1。对象应该有一个setter函数:set
2。创建ObjectAnimation对象一般是
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueBtn, "alpha", 1f,0f);
像ofFloat之类的工场方法,第一个参数为对象名(这个也就是我们的view类了),第二个为属性名,后面的参数为可变参 数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的 getter方法:get
3。如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。正常情况驼峰命名法都是get和set方法对应的出现
valueBtn=(Button) findViewById(R.id.valueAnimation); valueBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueBtn, "alpha", 1f,0f); objectAnimator.setDuration(1000); objectAnimator.start(); } });
这个就是ObjectAnimator简单的用法,通过这个我们也可以监听动画的开始和结束,上面有介绍过AnimatorListener的监听,如下:
objectAnimator.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { // TODO Auto-generated method stub } @Override public void onAnimationRepeat(Animator animation) { // TODO Auto-generated method stub } @Override public void onAnimationEnd(Animator animation) { // TODO Auto-generated method stub } @Override public void onAnimationCancel(Animator animation) { // TODO Auto-generated method stub } });
当是我们有时候不需要取监听动画的取消或者重复,这些代码在这里显然是多余的,这个时候我们就可以使用AnimatorListenerAdapter这个适配器来进行监听了,如下
objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // TODO Auto-generated method stub super.onAnimationEnd(animation); } @Override public void onAnimationStart(Animator animation) { // TODO Auto-generated method stub super.onAnimationStart(animation); } });
这个就只关心我们的动画开始和介绍,其它就不需要了,代码看起来简洁了很多。ObjectAnimator当然也有setInterpolator()和setStartDelay()等一系列方法,这些的话就和我们上面的说的tween Animation动画方法是一样的。如果我们想要同时实现很多个动画就需要AnimatorSet这个类来实现,如下代码:
AnimatorSet set=new AnimatorSet(); ObjectAnimator alphaAnimator=ObjectAnimator.ofFloat(valueBtn, "alpha", 0f,1f); ObjectAnimator xAnimator=ObjectAnimator.ofFloat(valueBtn, "translationX", 0f,5f,10f); ObjectAnimator yAnimator=ObjectAnimator.ofFloat(valueBtn, "translationY", 0f,5f,10f); ObjectAnimator rotateYAnimator=ObjectAnimator.ofFloat(valueBtn, "rotationX", 0f,90f); set.play(alphaAnimator).before(xAnimator); set.play(xAnimator).with(yAnimator); set.play(yAnimator).after(rotateYAnimator); set.setDuration(2000); set.start();
上面就是使用AnimatorSet方法,这个方法提供了before,with,after方法,按上面代码的意思就是alphaAnimator先执行,之后到xAnimator,yAnimator和xAnimator是同时执行的,执行完yAnimator和xAnimator之后就执行rotateYAnimator,看上面的字面意思也很容易理解了。
在实现过程中经常使用一些动画属性:
1。translationX,translationY,x,y
这些translationX和x,TranslationY和y是用区别的,下面来看看这个区别在哪里(我们这里以X坐标为例)
valueBtn=(Button) findViewById(R.id.valueAnimation); Log.i("itchq", "valueBtn.getLeft()="+valueBtn.getLeft()); Log.i("itchq", "valueBtn.getX()="+valueBtn.getX()); Log.i("itchq", "valueBtn.getTranslationX()="+valueBtn.getTranslationX());
上面的代码中看一默认打印的信息是:
这个默认都是为0的,当我使用translationX动画之后
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueBtn, "translationX", 0f,100f); objectAnimator.setDuration(1000); objectAnimator.start(); objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // TODO Auto-generated method stub Log.i("itchq", "valueBtn.getLeft()="+valueBtn.getLeft()); Log.i("itchq", "valueBtn.getX()="+valueBtn.getX()); Log.i("itchq", "valueBtn.getTranslationX()="+valueBtn.getTranslationX()); } });
动画结束之后打印的信息如下
这个时候我们再使用x动画之后
还是一样的,这个主要是因为这个getLeft为0,那么我们这个时候把getLeft设置为20时,当是translationX时动画之后打出的log是
这个时候的x不再是100了而是120了,再设置为x,看一下结果
这个时候的getTranslationX()不再是100了,而是80,所以无论啥样应用动画,getLeft的值是不会变的,而TranslationX的值是为最终位置于布局时初始位置的差,即“最终位置-getLeft()",而x为最终位置之和,即”getLeft()+getTranslationX()“,所以当getLeft为0的时候就会发现两个值是相等的。
2。rotation,rotationX,rotationY:旋转,rotation用于2D旋转角度,3D中用到后两个
3。scaleX,scaleY:缩放
4。alpha:透明度
Keyframe
keyFrame是一个 时间/值 对,通过它可以定义一个在特定时间的特定状态,而且在两个keyFrame之间可以定义不同的Interpolator,就相当多个动画的拼接,第一个动 画的结束点是第二个动画的开始点。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的 KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如以下代码:
Keyframe kf0 = Keyframe.ofInt(0, 400); Keyframe kf1 = Keyframe.ofInt(0.25f, 200); Keyframe kf2 = Keyframe.ofInt(0.5f, 400); Keyframe kf4 = Keyframe.ofInt(0.75f, 100); Keyframe kf3 = Keyframe.ofInt(1f, 500); PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3); ObjectAnimator widthAnim = ObjectAnimator.ofPropertyValuesHolder(valueBtn, pvhRotation); widthAnim.setDuration(2000); widthAnim.start();
上述代码的意思为:设置valueBtn对象的width属性值使其:
开始时 Width=400
动画开始1/4时 Width=200
动画开始1/2时 Width=400
动画开始3/4时 Width=100
动画结束时 Width=500
第一个参数为时间百分比,第二个参数是在第一个参数的时间时的属性值。定义了一些Keyframe后,通过PropertyValuesHolder类的方法ofKeyframe封装,然后通过ObjectAnimator.ofPropertyValuesHolder获得Animator。
PropertyValuesHolder
如果需要对一个View的多个属性进行动画可以用ViewPropertyAnimator类,该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f); ObjectAnimator x_yAnimator=ObjectAnimator.ofPropertyValuesHolder(valueBtn, pvhX, pvhY); x_yAnimator.setDuration(1000); x_yAnimator.start();
上面这段代码就是同时进行X轴和Y轴的动画