Android---动画机制(二)---属性动画

本文深入探讨Android 3.0引入的属性动画特性,解释如何使用ObjectAnimator进行2D/3D旋转、平移、缩放和透明度变化。还介绍了PropertyValuesHolder、ValueAnimator、 AnimatorSet的用法,以及动画事件监听和View的animate()方法。通过实例展示了如何创建和执行属性动画。
摘要由CSDN通过智能技术生成

属性动画是3.0推出的新特性,和View动画不同,他对对象进行了扩展,属性动画可以对任何对象做动画.在Animator框架中使用最多的就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的属性值,使用多个ObjectAnimator组合到AnimatorSet中形成一个动画.
在这里说明,动画默认的时间间隔是300ms,默认帧率10ms/帧
下面对属性动画做一一的介绍:

ObjectAnimator

 ObjectAnimator animator=ObjectAnimator.ofFloat(
                        //需要操作的View
                        textView,
                        //要操作的属性
                        "translationX",
                        //从200点坐标移动到300点坐标
                        200,300);
                animator.setDuration(300);
                animator.start();
  • rotation rotationX rotationY
    三个属性控制View对象围绕支点进行2D和3D的旋转.
  • translationX和translationY
    控制着View对象从它布局容器的左上角坐标偏移量的位置
  • scaleX和scaleY.
    控制着View对象围绕他的支点进行2D缩放 (1.1.5F)由1倍放大至1.5倍
  • alphy
    表示View对象的alpha透明度.默认是1不透明,0代表完透明

或者通过XML文件来展示属性动画,建议还是通过代码,比如说在不知道屏幕宽度的时候我们没法执行一些效果

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">  //表示动画组合是按顺序执行还是一起执行
    <objectAnimator
        android:propertyName="x"      //属性名称
        android:duration="3000"       //执行时间
        android:valueFrom="300"       //属性的起始值
        android:valueTo="0"           //属性的结束值
        android:startOffset="0"       //表示动画的延迟时间
        android:repeatCount="3"       //表示动画的重复次数
        android:repeatMode="reverse"  //表示动画的重复模式 reverse表示逆向重复,restart表示连续重复
        android:valueType="floatType" //表示属性的类型
    />
</set>

然后通过JAVA代码执行

   AnimatorSet set= 
          (AnimatorSet) AnimatorInflater.loadAnimator(MainActivity.this,R.animator.zc);
   set.setTarget(textView);
   set.start();

PropertyValuesHolder

类似视图动画中的AnimationSet,在属性动画中,如果针对一个对象多个属性同时作用多种动画,可以使用PropertyValuesHolder来实现.

PropertyValuesHolder pvh1=PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder pvh2=PropertyValuesHolder.ofFloat("scaleX",1f,0.5f);
PropertyValuesHolder pvh3=PropertyValuesHolder.ofFloat("scaleY",1f,0.5f);
PropertyValuesHolder pvh4=PropertyValuesHolder.ofFloat("alphy",1,0,1);

ObjectAnimator.ofPropertyValuesHolder(textView,pvh1,pvh2,pvh3,pvh4)
                        .setDuration(3000).start();

ValueAnimatior

本身不提供效果,更像是一个数值发生器,用来产生具有一定规律的数字 .

                ValueAnimator animator=ValueAnimator.ofInt(0,100);

                animator.addUpdateListener(
                        new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                       textView.setText((Integer) animation.getAnimatedValue()+"");
                    }
                });
                animator.setTarget(textView);
                animator.setDuration(3000);
                animator.start();

这里写图片描述

动画事件的监听

一个完整的动画具有Start Repeat End Cancel四个过程.通过Android提供了接口可以方便的监听这四个实践

                ObjectAnimator animator=ObjectAnimator.ofFloat(textView,"alpha",0.5f);
                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) {

                    }
                });

AnimatiorSet

AnimatiorSet不仅能够实现PropertyValuesHolder的效果,同时也能更为精确的控制顺序

                ObjectAnimator animator1 = 
                        ObjectAnimator.ofFloat(textView,"translationX", 300f);
                ObjectAnimator animator2 = 
                        ObjectAnimator.ofFloat(textView,"scaleX", 1f, 0.5f);
                ObjectAnimator animator3 = 
                        ObjectAnimator.ofFloat(textView,"scaleY", 1f, 0.5f);
                ObjectAnimator animator4 = 
                        ObjectAnimator.ofFloat(textView,"alphy", 1, 0, 1);

                AnimatorSet set=new AnimatorSet();
                set.setDuration(1000);
                set.playSequentially(animator1,animator2,animator3,animator4);
                set.start();

设置如何播放动画由以下几种:

  • playTogether 动画一起执行
  • playSequentially 按设置的动画一个一个的执行
  • -

包装原始对象,提供get和set方法

    private static class WrapperView{
        private View mTarget;

        public WrapperView(View target){
            mTarget=target;
        }

        public int getWidth(){
            return mTarget.getLayoutParams().width;
        }
        public void setWidth(int width){
            mTarget.getLayoutParams().width=width;
            mTarget.requestLayout();
        }
    }
WrapperView wrapperView=new WrapperView(v);
ObjectAnimator.ofInt(wrapperView,"width", 500).setDuration(8000).start();

View的animate方法

属性动画的一种简写方式

                textView.animate()
                        .alpha(0)
                        .y(300)
                        .setDuration(3000)
                        .withStartAction(new Runnable() {
                            @Override
                            public void run() {
                            }
                        })
                        .withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                    }
                                });
                            }
                        }).start();

属性动画中的标签对应

<set>----AnimatorSet
<animator>----ValueAnimator
<objectAnimator>----ObjectAnimator

属性动画实例:

效果图:
这里写图片描述

代码如下所示:

布局代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.zc.myapplication.MainActivity"
    android:orientation="vertical">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:background="@android:color/holo_blue_bright"
       android:gravity="center_vertical"
       android:onClick="llClick"
       android:orientation="horizontal">

      <ImageView
          android:id="@+id/app_icon"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:src="@mipmap/ic_launcher" />

      <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginLeft="5dp"
          android:gravity="left"
          android:text="Click me"
          android:textSize="30sp" />

   </LinearLayout>

   <LinearLayout
       android:id="@+id/hidden_view"
       android:layout_width="match_parent"
       android:layout_height="40dp"
       android:background="@android:color/holo_orange_light"
       android:orientation="horizontal"
       android:visibility="gone"
       >

   <ImageView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:src="@mipmap/ic_launcher" />

   <TextView
       android:id="@+id/tv_hidden"
       android:layout_width="wrap_content"
       android:layout_height="match_parent"
       android:gravity="center"
       android:text="I Am Hidden"
       android:textSize="20sp" />
   </LinearLayout>
</LinearLayout>

JAVA代码:

public class MainActivity extends AppCompatActivity {
    private LinearLayout mHiddenView;
    private float mDensity;
    private int mHiddenViewMeasuredHeigth;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHiddenView= (LinearLayout) findViewById(R.id.hidden_view);
        //获取像素密度
        mDensity=getResources().getDisplayMetrics().density;

        //获取布局的高度  这里的40就是View设置的40dp
        mHiddenViewMeasuredHeigth= (int) (mDensity*40+0.5);
    }
    public void llClick(View view) {
        if (mHiddenView.getVisibility()==View.GONE){
            //打开动画
            animateOpen(mHiddenView);
        }else {
            //关闭动画
            animateClose(mHiddenView);
        }
    }

    private void animateOpen(LinearLayout mHiddenView) {
        mHiddenView.setVisibility(View.VISIBLE);
        ValueAnimator animator=createDropAnimator(
                mHiddenView
                ,0
                ,mHiddenViewMeasuredHeigth);
        animator.start();
    }

    private void animateClose(final LinearLayout mHiddenView) {
        int origHeigth=mHiddenView.getHeight();
        ValueAnimator animator=createDropAnimator(
                mHiddenView
                ,origHeigth
                ,0);
        animator.start();
        //监听动画的结束,结束以后将View设置为GONE
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mHiddenView.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

    }

    private ValueAnimator createDropAnimator(final LinearLayout mHiddenView, int start, int end) {
        ValueAnimator animator=ValueAnimator.ofInt(start,end);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value= (int) animation.getAnimatedValue();
                ViewGroup.LayoutParams layoutParams=
                        mHiddenView.getLayoutParams();
                layoutParams.height=value;
                mHiddenView.setLayoutParams(layoutParams);
            }
        });
        return  animator;
    }
}

在这里说明一下为什么要设置一个动画的监听,因为如果不设置的话那么将隐藏的View显示以后,再执行点击事件将View隐藏,在点击以后View不会再显示出来,因为

    public void llClick(View view) {
        if (mHiddenView.getVisibility()==View.GONE){
            //打开动画
            animateOpen(mHiddenView);
        }else {
            //关闭动画
            animateClose(mHiddenView);
        }
    }

只有当判断View为GONE的时候才会隐藏,我们只是把View给显示高度为0了 但是并没有隐藏.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值