android动画监听不跑onanimationrepeat,Android 动画之属性动画(三)

Android 动画之属性动画(三)#

Animation Listeners##

前面的两节中都或多或少提到了动画监听 Animation Listeners 这个概念。它用来监听动画的过程,并且提供一些接口让你实现一些逻辑。比如说你想在动画开始的时候进行一些操作,就需要为这个动画设置一个监听器,然后实现你的逻辑,这样,当监听器监听到动画开始,就回去实现你的逻辑

Animator.AnimatorListener

Animator 类当中提供了一个 addListener() 方法,这个方法接收一个接口类 AnimatorListener ,获得该接口后就可以重写以下四个方法:

onAnimationStart() - 当动画开始的时候调用

onAnimationEnd() - 当动画结束后调用

onAnimationRepeat() - 当动画重复播放时调用

onAnimationCancel() - 当动画被取消的时候调用,并且在调用完这个方法后,会自动调用 onAnimationEnd() 方法

下面的例子中为每一段代码实现了一个逻辑:弹出对应的文字

anim.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animator) {

Toast.makeText(MainActivity.this, "start", Toast.LENGTH_LONG).show();

}

@Override

public void onAnimationEnd(Animator animator) {

Toast.makeText(MainActivity.this, "End", Toast.LENGTH_LONG).show();

}

@Override

public void onAnimationCancel(Animator animator) {

Toast.makeText(MainActivity.this, "Cancel", Toast.LENGTH_LONG).show();

}

@Override

public void onAnimationRepeat(Animator animator) {

Toast.makeText(MainActivity.this, "rapeat", Toast.LENGTH_LONG).show();

}

});

anim.start();

//添加一个按钮,按钮的功能用于cancel动画

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

anim.cancel();

}

});

来看运行后效果

65621fb06bef

65621fb06bef

65621fb06bef

按下cancel键后

65621fb06bef

65621fb06bef

当然如果你不想把所有方法都重写的话,可以使用 AnimatorListenerAdapter 类,如下

anim.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

}

});

这样的话就可以选择自己想要重写方法进行重写

ValueAnimator.AnimatorUpdateListener

Animator 类当中提供了一个 addUpdateListener() 方法,这个方法接收一个接口类 AnimatorUpdateListener ,获得该接口后就可以重写 onAnimationUpdate() 方法,这个方法为动画提供每一帧的监听,之前在(一)的时候提到,每一帧其实是用一个 value 值来控制的,所以通常情况下我们都需要在每一帧监听的时候获得这个 value 值,就需要调用 ValueAnimator.getAnimatedValue() 方法来获得。

ValueAnimator vanim = ValueAnimator.ofInt(0,10,20);

vanim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator valueAnimator) {

//如果之前的ValueAnimtor指定的是Int的i话,那么返回的Value就是int类型,

也就是返回值类型与你创建的类型一致

int value = (int) valueAnimator.getAnimatedValue();

}

});

Animating Layout Changes to ViewGroups##

属性动画不仅可以让你对 view 类进行动画操作,同时它还可以用于 viewgroup 类的变化进行动画操作。比如说你有一个 gridLayout ,你需要在里面添加按钮,那么按钮加到 gridLayout 是一个动画的过程,系统会有一个默认的动画。如果想要改变这个默认的动画效果,就可以借助 LayoutTransition 类来为这个 gridLayout 修改动画效果。使用步骤:

新建一个 LayoutTransition

对 LayoutTransition 通过调用 setAnimator ( int transitionType, Animator animator ) 设置自定义的动画

为所需要的 ViewGroup 通过 setLayoutTransition( LayoutTransition ) 添加一个 LayoutTransition

需要注意的是在setAnimator()中的第一个参数 transitionType 决定了动画的类型,一共有四种:

APPEARING:元素在容器中显现时需要动画显示

CHANGE_APPEARING:由于容器中要显现一个新的元素,其它元素的变化需要动画显示

DISAPPEARING:元素在容器中消失时需要动画显示

CHANGE_DISAPPEARING:由于容器中某个元素要消失,其它元素的变化需要动画显示

代码:

LayoutTransition layoutTransition = new LayoutTransition();

//设置这个动画为缩放

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(null,"scaleX",0f,1f);

layoutTransition.setAnimator(LayoutTransition.APPEARING,objectAnimator);

gridContainer.setLayoutTransition(layoutTransition);

//通过点击添加按钮,往gridContainer添加button,这里就涉及到了上面第一种类型的动画:appear

add_button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

Button newButton = new Button(MainActivity.this);

newButton.setText(String.valueOf(num++));

gridContainer.addView(newButton, Math.min(1, gridContainer.getChildCount()));

}

});

可以看到,按钮出现的时候是以缩放的形式出现的

65621fb06bef

65621fb06bef

Using a TypeEvaluator

在第一篇的时候我们就有讲到 Evaluator 这个类。请复习 Android 动画之属性动画(一)>Evaluator 类。有些时候你需要返回的动画返回的 value 不是系统默认的 Int,Float 或 Color 类型的,那么你就可以自己自定义这个 Evaluator 来返回你所需要的类型!比如说一个坐标点。这也是 属性动画 比 补间动画 强大的精髓所在。

那要如何自己实现呢,首先需要继承 TypeEvaluator 接口,然后重写里面的 evaluate() 方法。

//其实FloatEvaluator也是继承TypeEvaluator,来实现的

public class FloatEvaluator implements TypeEvaluator {

//注意看到fraction参数,在第一篇里面提到的参数

public Object evaluate(float fraction, Object startValue, Object endValue) {

float startFloat = ((Number) startValue).floatValue();

return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);

}

}

下面我们来实现一个返回一个坐标点的 Evaluator

首先新建一个点类:Point

public class Point {

private float x;

private float y;

public Point(float x,float y) {

this.x = x;

this.y = y;

}

public float getX(){

return x;

}

public float getY(){

return y;

}

}

然后我们新建一个 PointEvaluator ,在里面要实现的是当我们传入一个初始点和结束点,然后实现平缓从初始点到结束点

public class PointEvaluator implements TypeEvaluator {

float x;

float y;

@Override

public Object evaluate(float fraction, Object s, Object e) {

Point startPoint = (Point) s;

Point endPoint = (Point) e;

float x = startPoint.getX()+fraction*(endPoint.getX()-startPoint.getX());

float y = startPoint.getY()+fraction*(endPoint.getY()-startPoint.getY());

Point point = new Point(x,y);

return point;

}

}

然后我们新建一个view,在view里面有一个绘制一个圆,通过对圆心坐标的动画实现球的动画

代码的思路就是在左上角画一个圆,然后对圆心坐标进行进行动画,为动画监听,每得到一个新的圆心坐标就重新绘制view,下面代码略长,耐心看是很容易看懂的

public class myView extends View {

Paint mpaint;

Point CurrentPoint = null;

float radius;

public myView(Context context) {

this(context, null);

}

public myView(Context context, AttributeSet attrs) {

super(context, attrs);

mpaint = new Paint();

mpaint.setStyle(Paint.Style.FILL);

mpaint.setColor(Color.BLUE);

radius = 25f;

}

//CurrentPoint用来记录当前圆心的位置,用来告诉canvas在哪绘制圆,Currentpoint为空时

则新建一个坐标点,然后设置动画

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (CurrentPoint == null) {

CurrentPoint = new Point(radius, radius);

drawCircle(canvas);

setAnimation();

} else {

drawCircle(canvas);

}

}

//根据当前坐标画圆

private void drawCircle(Canvas canvas) {

canvas.drawCircle(CurrentPoint.getX(), CurrentPoint.getY(), radius, mpaint);

}

//设置动画。每当有新的point返,则通知view重绘

public void setAnimation() {

ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(),

new Point(radius,radius),

new Point(getWidth() - radius, getHeight() - radius));

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator valueAnimator) {

CurrentPoint = (Point) valueAnimator.getAnimatedValue();

invalidate();

}

});

valueAnimator.setDuration(2000);

valueAnimator.start();

}

}

到此我们已经完成了自定义的 Evaluator ,请自行运行查看效果

Using Interpolators##

前面已经提到过 Interpolators 的作用,这里不再重复。如果你没有找到适合自己的 Interpolators ,那么就可以继承 Interpolators 然后重写 getInterpolation()

方法

以下是系统实现 AccelerateDecelerateInterpolator 和 LinearInterpolator 的算法:

AccelerateDecelerateInterpolator

public float getInterpolation(float input) {

return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;

}

LinearInterpolator

public float getInterpolation(float input) {

return input;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值