Android动画

一.动画分类

Android动画分为两大类,View Animation(视图动画)和 Property Animation(属性动画)。其中视图动画包括Tween Animation(补间动画)和 Frame Animation(逐帧动画);属性动画包括ValueAnimator 和 ObjectAnimator。

补间动画,就是对控件进行透明度(alpha)、旋转(rotate )、位移(translate)、缩放(scale)等操作。逐帧动画,就是把一系列静态图进行动态展示。视图动画只能对派生自 View 的控件实例起作用,针对该控件设置动画,若要在1min中把该控件的背景色从黑色变为白色,则要用到属性动画。属性控件能够通过改变控件内部的属性值来实现动画效果,这一点视图动画无法做到。还有一点,视图动画只是改变了 View 显示的大小,而没有改变 View 的响应区域,若要改变视图的响应区域,就要使用属性动画。

二. ValueAnimator

1.使用

ValueAnimator animator = ValueAnimator.ofInt(100, 150);
animator.setDuration(4000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
	@Override
	public void onAnimationUpdate(ValueAnimator animation) {
		//通过 getAnimatedValue()值类型与初始设置动画时的值类型相同
		int v = (int)animation.getAnimatedValue();
		Log.d(TAG, "onAnimationUpdate: v = " + v);
		tv_test.layout(v, v, v+tv_test.getWidth(), v+tv_test.getHeight());
	}
});
//监听动画的实时变化状态
animator.setInterpolator(new OvershootInterpolator(10f));
//不想实现Animator.AnimatorListener中的所有接口,你可以通过继承AnimatorListenerAdapter
animator.addListener(new AnimatorListenerAdapter() {
	@Override
	public void onAnimationEnd(Animator animation) {
		Log.d(TAG, "onAnimationEnd");
	}
});

animator.setRepeatCount(4);
animator.setRepeatMode(ValueAnimator.RESTART);
//animator.setRepeatMode(ValueAnimator.REVERSE);
animator.start();

2. animator.addListener()可以实现Animator.AnimatorListener接口

animator.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
    }
    @Override
    public void onAnimationEnd(Animator animation) {
    }
    @Override
    public void onAnimationCancel(Animator animation) {
    }
    @Override
    public void onAnimationRepeat(Animator animation) {
    }
});

也可以继承AnimatorListenerAdapter,单独实现某一个或全部接口。

3. animator.setRepeatCount();设置重复次数。animator.setRepeatMode();设置重复模式:ValueAnimator.RESTART原样重复,ValueAnimator.REVERSE反向重复。

4. ValueAnimator.ofInt(100, 150),表示动画时的变化范围;animation.getAnimatedValue()表示当前运动点的值,为int类型,和设定动画初始值时用的是 ofInt()函数有关。若使用ValueAnimator.ofFloat(),则animation.getAnimatedValue()返回float类型的值。当使用ValueAnimator.ofObject(TypeEvaluator evaluator, Object... values)时,就要重写TypeEvaluator的evaluate()方法,把小数进度转换成对应的数值位置。

private class CharEvaluator implements TypeEvaluator<Character> {
	@Override
	public Character evaluate(float fraction, Character startValue, Character endValue) {
		Log.d(TAG, "fraction: " + fraction + ", " + startValue + ", " + endValue);
		if (fraction > 1){
			fraction = 1;
		}
		int v = (int)(startValue+(endValue-startValue)*fraction);
		Log.d(TAG, "evaluate: v = " + v);
		return (char)v;
	}
}

从‘a’变到‘z’

ValueAnimator animator = ValueAnimator.ofObject(new CharEvaluator(), 'a', 'z');//创建一个字母从 A 变化到 Z的动画
animator.setDuration(10000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
	@Override
	public void onAnimationUpdate(ValueAnimator animation) {
		//通过 getAnimatedValue()值类型与初始设置动画时的值类型相同
		char v = (char) animation.getAnimatedValue();
		Log.d(TAG, "onAnimationUpdate: v = " + v);
		tv_test.setText(String.valueOf(v));
	}
});
//监听动画的实时变化状态
animator.setInterpolator(new OvershootInterpolator(2f));
//不想实现Animator.AnimatorListener中的所有接口,你可以通过继承AnimatorListenerAdapter
animator.addListener(new AnimatorListenerAdapter() {
	@Override
	public void onAnimationEnd(Animator animation) {
		Log.d(TAG, "onAnimationEnd");
	}
});

animator.setRepeatCount(2);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.start();	

三.ObjectAnimator

ObjectAnimator是在ValueAnimator 的基础上派生的,可以监听View的移动,动态改变背景色及改变显示内容等操作,也可以改变View的属性,也就是说ObjectAnimator可以直接对任意对象的任意属性进行动画操作。

ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(imgBtn, "scaleX", 1.2f, 0.5f, 1f)
	.setDuration(300);
scaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
	@Override
	public void onAnimationUpdate(ValueAnimator animation) {
		float values = (Float) animation.getAnimatedValue();
		if(imgBtn != null) {
			imgBtn.setScaleX(values);
			imgBtn.setScaleY(values);
		}
	}
});
scaleAnimator.start();

利用属性动画,实现Button的宽度变化。

方式1:包装原始对象,实现width的get/set方法

    private static class ViewWrapper{
        private View mTarget;
        public ViewWrapper(View v){
            mTarget = v;
        }

        public int getWidth(){
            int w = mTarget.getLayoutParams().width;//获取xml文件中定义的宽度
            Log.d(TAG, "getWidth:w = " + w);
            w = w < 0 ? mTarget.getWidth() : w;
            Log.d(TAG, "getWidth: " + w);
            return w;
        }
        public void setWidth(int w){
            Log.d(TAG, "setWidth: " + w);
            mTarget.getLayoutParams().width = w;
            mTarget.requestLayout();
        }
    }
ViewWrapper viewWrapper = new ViewWrapper(mBtn);            
Log.d(TAG, "btn width: " + viewWrapper.getWidth());
ValueAnimator animator = ObjectAnimator.ofInt(viewWrapper, "width", 500);
animator.setDuration(2000).start();

方式2:监听动画过程,自己改变属性

public void onValueAnimChangeWidth(View v){
	ValueAnimator animator = ValueAnimator.ofInt(1, 100);
	animator.setDuration(2000);
	final IntEvaluator evaluator = new IntEvaluator();
	final int startVal = mBtn.getWidth();//控件真实宽度
	final int endVal = 500;
	Log.d(TAG, "startVal: " + startVal);
	animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
		@Override
		public void onAnimationUpdate(ValueAnimator animation) {
			//Log.d(TAG, "onAnimationUpdate: " + animation.getAnimatedValue());
			float fraction = animation.getAnimatedFraction();
			Log.d(TAG, "fraction: " + fraction);
			int w = evaluator.evaluate(fraction, startVal, endVal);
			mBtn.getLayoutParams().width = w;
			mBtn.requestLayout();
		}
	});
	animator.start();
}

参考:

Android-Animation 总结(二(Valueanimator))

Android属性动画(Animator)的优势

ValueAnimator 基本使用

getLayoutParams().width/getMeasuredWidth()/getWidth()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值