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

android动画之从源码角度分析动画原理(一)

2015-07-30 20:58 651 查看

介绍

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);
}
}
}



4000
面那个就是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.in
13b9b
ternal.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轴的动画
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 animation android