自定义控件——属性动画

1.1 ValueAniamor的基本使用
1.1.1 为何要引入属性动画

  • 属性动画是为了弥补视图动画的不足而设计的,能够实现补间动画无法实现的功能。

从属性动画的名字我们知道它应该是用于操作控件的属性的。

补间动画的一个缺点
当我们利用补间动画绘制一个矩形,并给它设置点击事件,然后将它从屏幕的左上角移动到右下角时,我们会发现当我门点击当前右下角的位置,并不会触发点击事件,而当我们点击左上角时却会触发点击事件。这说明补间动画虽然可以对控件作动画,但是并没有改变控件内部的属性值。而使用属性动画来是是实现这一点就很容易了。

1.1.2 ValueAnimator的简单使用
ValueAnimator不会对控件执行任何操作。只能给他设定值的变化,通过值的变化来实现渐变,缩放等等效果。
1.初步使用

(1). 创建ValueAnimator

ValueAnimator animator=ValueAnimator.ofInt(0,400);
animator.setDuration(1000);
animator.start();

(2)添加监听事件

ValueAnimator animator=ValueAnimator.ofInt(0,400);
animator.setDuration(1000);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
		@Override
		public void inAnimationUpdate(ValueAnimator animation){
		int value=(Integer)animation.getAnimatedValue();
		Log.d("value"+value);
		}
});

animator.start();

使用addUpdateListener()函数添加一个监听事件,在函数传回的结果中,animation表示当前ValueAnimator实例,通过animation.getAnimatedValue()函数得到当前值。这就是ValueAnimator,对指定值区间进行动画运算,总之:
ValueAniamtor 只负责对指定值区间进行动画运算
我们需要对运算过程进行监听,然后自己对控件执行动画操作

现在我们利用属性动画来实现补间动画平移的问题
在线性布局中添加以下代码:

 <Button 
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="start"
        android:id="@+id/btn"/>

    <TextView
        android:id="@+id/tv"
        android:background="#fff000"
        android:text="Hello"
        android:padding="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

java代码如下:

 private TextView tv ;
    private Button btn ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById (R.id.tv);
        btn = (Button) findViewById(R.id.btn) ;
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doAnimation();
            }
        });
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast. makeText(MainActivity . this,"clicked me ", Toast.LENGTH_SHORT ) . show ();  
            }
        });
    }
    private void doAnimation() {
        ValueAnimator animator=ValueAnimator.ofInt(0,300);
        animator.setDuration(1000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int value=(Integer)valueAnimator.getAnimatedValue();
                tv.layout(value,value,value+tv.getWidth(),value+tv.getHeight());
            }
        });
        animator.start();
    }

从最后的结果中知道,在控件动画结束后,是仍然可以响应点击事件。

1.1.3 ValueAnimator的常用函数
(1)ofInt()和OfFloat()

public static ValueAnimator ofInt(int ... values)
public static ValueAnimator ofFloat(float ... values)

这两个函数的参数都是可变长参数,传进去的参数列表就是动画的变化范围。

常用函数汇总:

//设置动画时长
ValueAnimator setDuration(long duration)
//获取valueAnimator运动时当前运动点的值
Object getAnimatedValue()
//开始动画
void start()
//设置循环次数
void setRepeatCount(int value)
//设置循环模式
void setRepeatMode(int value)
//取消动画
void cancel()

1.2 自定义插值器与Evaluator
与view Animation一样,ValueAnimator也可以设置插值器,而且还可以设置Evaluator
1.2.1 自定义插值器

先来查看以下LinearInterpolator的源码:




public class LinearInterpolator extends BaseInterpolator {
    public LinearInterpolator() {
        throw new RuntimeException("Stub!");
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
        throw new RuntimeException("Stub!");
    }

    public float getInterpolation(float input) {
        throw new RuntimeException("Stub!");
    }
}

public interface Interpolator extends TimeInterpolator {
}

public abstract class BaseInterpolator implements Interpolator {
    public BaseInterpolator() {
        throw new RuntimeException("Stub!");
    }
}

LinearInterpolator继承于BaseInterpolator,BaseInterPolator继承于Interpolator,Interpolator继承于TimeInterpolator
查看TimeInterpolator如下:

public interface TimeInterpolator {
    float getInterpolation(float var1);
}

它里面只有一个getInterpolation(float input)函数

  • 参数input:input参数时float类型,它的取值范围为0~1,表示当前动画的进度,取0时表示动画刚开始,取1时表示动画结束,取0.5表示动画位于中间位置等等。
  • 返回值:表示当前实际想要显示的进度,取值可以超过1,也可以小于0

看过插值器的具体实现我们来分析以下这个例子的具体实现。

ValueAnimator animator=ValueAnimator.ofInt(0,300);
        animator.setDuration(1000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int value=(Integer)valueAnimator.getAnimatedValue();
            }
        });
        animator.start();

其实先就如下公式:
当前的值=0+(300-0)*显示进度;

所以自定义插值器我们只需要是实现TimeInterpolator接口就可以了

public class MyInterpolator implements TimeInterpolator{
		@Override
		public float getInterpolation(float input){
				return 1-input;//返回数学公式,数学公式决定了插值器的效果
		}
}

使用时:

animator.setInterpolator(new MyInterpolator());

1.2.2 Evaluator
在这里插入图片描述
改图讲述了从定义动画的数值区间到AnimatorUpdateListener中得到当前动画所对应数值的整个过程。
(1)ofInt(0,400):表示指定动画的数值区间,从0到400
(2)插值器:表示动画开始后,通过插值器会返回当前动画进度所对应的数值进度,但这个数值是以小数表示的
(3)Evaluator:我们通过监听器拿到的是当前动画所对应的具体数值,而不是用小数表示的数值。所以必须有一个地方会根据当前的数值进度将其转换为对应的数值,这个地方就是Evaluator,用于将插值器返回的数值进度转换为对应的数值。
(4)监听器返回:通过在AnimatorUpdateListener监听器中使用animation.getAnimateValue()函数拿到Evaluator中返回的数值。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值