当前位置: 首页>前端>正文

Android基础之动画(下)

学习资料

  • Android动画
  • Android的几种动画定义与使用
  • 百度翻译
  • Android中getX(),getY(),getTop,getRawY()等的区别

简介

  • Android基础之动画(上)中学习了补间动画和帧动画。
  • 这篇就讲属性动画和过渡动画

属性动画(PropertyAnimation)

  • 作用对象:任意 Java 对象,不再局限于 视图View对象;实现的动画效果:可自定义各种动画效果,不再局限于4种基本变换:平移、旋转、缩放 & 透明度
  • 主要特点是,属性动画是改变了动画对象的属性来实现动画的,比如平移是真的改变了对象的坐标信息的。
  • 和其他动画一样,也可以代码实现和xml文件实现。

使用

xml文件实现动画
  • 使用xml方式实现属性动画的时,需要先在res目录下创建animator文件夹。
  • 然后新建xml文件,写好你的动画文件
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
    <objectAnimator
        android:duration="4000"
        android:propertyName="alpha"
        android:valueFrom="1"
        android:valueTo="0.5"
        android:valueType="floatType"/>
    <objectAnimator
        android:duration="4000"
        android:propertyName="width"
        android:valueFrom="240"
        android:valueTo="480"
        android:valueType="intType"
        />
    <objectAnimator
        android:propertyName="rotation"
        android:duration="4000"
        android:valueFrom="90"
        android:valueTo="145"
        android:valueType="floatType"/>
</set>
  • 然后就在代码中使用啦,和普通动画差不多滴。
    private ImageView img_beauty;
    private Animator animator;
    private void initAnimatorXML(){
        animator = AnimatorInflater.loadAnimator(this,R.animator.beauty_animtor);
        animator.setTarget(new WrapView(img_beauty));
        animator.start();
    }
  • 最关键的一步来了,如果使用ObjectAnimator的话,必须要为你操作的对象实现相应的getXX()和setXX()的方法,这个XX就是你需要改变的属性.
  • 我重新试了试,发现不用包装也可以运行,所以不用实现下面这些方法。直接用
    private void initAnimatorXML() {
        animatorXML = AnimatorInflater.loadAnimator(this, R.animator.beauty_animtor);
        animatorXML.setTarget(img_beauty);
    }
代码实现动画
  • 直接使用ObjectAnimator类。其实也可以用ValueAnimator,但是ObjectAnimator就是继承自ValueAnimator,所以肯定是ObjectAnimator是有优化,会用一个就OK了,这里我直接用的ObjectAnimator;不用去管ValueAnimator;
  • 首先是透明度动画
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img_beauty,"alpha",1.0f,0.5f);
        objectAnimator.setDuration(4000);
  • 这里贴出我写的动画,不一个个写了
  ObjectAnimator objectAnimator;
        animator = null;
        //透明度
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
        //角度rotation
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
        //缩放 这里传入的值是倍数,即原本图片的宽度的倍数
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleX", 0, 1);
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleY", 1, 0);
        //平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
        //这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
        float x = img_beauty.getX();
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
        //背景颜色
        //API23才能使用这个方法
        //这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。
        objectAnimator = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
                getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));  
        //控件宽度
        int width = img_beauty.getLayoutParams().width;
        objectAnimator = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);
        
        animator = objectAnimator;
        animator.setDuration(4000);
  • 哦,上面话横线的也不算说错,比如上面最后一个动画,宽度改变的动画,因为我的ImageView没有setWidth的方法,就会报错,告诉我需要一个相关的方法,这样就必须有一个包装类,来包装我的ImageView,然后使用。、
  class WrapView {
        private View view;
        private int width;
        private float alpha;

        private float rotation;

        public WrapView(View view) {
            this.view = view;
        }

        public int getWidth() {
            if (view == null) return 0;
            return view.getLayoutParams().width;
        }

        public void setWidth(int w) {
            this.width = w;
            view.getLayoutParams().width = w;
            view.requestLayout();//刷新布局
        }

        public float getAlpha() {
            if (view == null) return 0;
            return view.getAlpha();
        }

        public void setAlpha(float alpha) {
            this.alpha = alpha;
            view.setAlpha(alpha);
            view.requestLayout();
        }

        public float getRotation() {
            if (view == null) return 0;
            return view.getRotation();
        }

        public void setRotation(float rotation) {
            this.rotation = rotation;
            view.setRotation(rotation);
            view.requestLayout();
        }
    }
动画合集AnimatorSet
  • 没什么好说的,动画肯定不能一个一个执行,肯定有需求要求一起是吧。
  • 大同小异,就是设置好动画以后,放入AnimatorSet中,按照自己想要的顺序灵活运用play,with,after,before等方法添加动画。
  private void initAnimatorSet() {
        AnimatorSet animatorSet = new AnimatorSet();
        //透明度
        Animator alpha = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
        //角度rotation

        Animator rotation = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
        //缩放 这里传入的值是倍数,即原本图片的宽度的倍数

        Animator scaleX = ObjectAnimator.ofFloat(img_beauty, "scaleX", 1, 2);

        Animator scaleY = ObjectAnimator.ofFloat(img_beauty, "scaleY", 2, 1);
        //平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
        //这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
        float x = img_beauty.getX();

        Animator translationX = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
        //背景颜色
        //API23才能使用这个方法
        //这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。

        Animator  backgroundColor = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
                getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));
        //控件宽度
        int width = img_beauty.getLayoutParams().width;
        Animator w = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);
        
        animatorSet.play(alpha)
                .with(rotation)//需要同时执行的动画用with
                .with(w)
                .with(translationX)
                .after(scaleX)//需要执行play之后执行的动画
                .before(scaleY);//需要执行play之前执行的动画
        
        animator = animatorSet;
        animator.setDuration(6000);
    }
  • 完整代码
package com.southwind.androidfoundation.animation;

import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.FloatValueHolder;

import com.southwind.androidfoundation.R;
import com.southwind.androidfoundation.fourassembly.base.BaseActivity;


/**
 * 属性动画
 */
public class PropertyAnimationActivity extends BaseActivity {

    private ImageView img_beauty;

    private Animator animator;
    private Animator animatorXML;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        setContentView(R.layout.activity_property_animation);
        super.onCreate(savedInstanceState);
        initData();
    }

    private void initData() {
//        initValueAnimator();
        initObjectAnimator();
        initAnimatorXML();
        initAnimatorSet();
    }

    @Override
    public void initView() {
        super.initView();
        img_beauty = findViewById(R.id.img_beauty);
    }

    private void initObjectAnimator() {
        ObjectAnimator objectAnimator;
        animator = null;
        //透明度
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
        //角度rotation
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
        //缩放 这里传入的值是倍数,即原本图片的宽度的倍数
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleX", 0, 1);
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "scaleY", 1, 0);
        //平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
        //这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
        float x = img_beauty.getX();
        objectAnimator = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
        //背景颜色
        //API23才能使用这个方法
        //这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。
        objectAnimator = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
                getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));
        //控件宽度
        int width = img_beauty.getLayoutParams().width;
        objectAnimator = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);
        animator = objectAnimator;
        animator.setDuration(4000);
    }

    private void initValueAnimator() {
        animator = null;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.5f);
        valueAnimator.setTarget(img_beauty);
        animator = valueAnimator;
        animator.setDuration(4000);
    }

    private void initAnimatorSet() {
        AnimatorSet animatorSet = new AnimatorSet();
        //透明度
        Animator alpha = ObjectAnimator.ofFloat(img_beauty, "alpha", 1.0f, 0.5f);
        //角度rotation

        Animator rotation = ObjectAnimator.ofFloat(img_beauty, "rotation", 90, 45);
        //缩放 这里传入的值是倍数,即原本图片的宽度的倍数

        Animator scaleX = ObjectAnimator.ofFloat(img_beauty, "scaleX", 1, 2);

        Animator scaleY = ObjectAnimator.ofFloat(img_beauty, "scaleY", 2, 1);
        //平移 这里想从原位置开始平移,那么第一个位置参数设置为0就行了
        //这里的getX()返回的就是0。但是这个值应该是触摸点距离控件的左边距的距离。不是很懂。
        float x = img_beauty.getX();

        Animator translationX = ObjectAnimator.ofFloat(img_beauty, "translationX", x, x + 50);
        //背景颜色
        //API23才能使用这个方法
        //这个还蛮好玩的,可以多种颜色,而且是线性变化,慢慢变化的。

        Animator  backgroundColor = ObjectAnimator.ofArgb(findViewById(R.id.btn_start_anim_java),"backgroundColor",
                getColor(R.color.purple_200), getColor(R.color.teal_200),getColor(R.color.black));
        //控件宽度
        int width = img_beauty.getLayoutParams().width;
        Animator w = ObjectAnimator.ofInt(new WrapView(img_beauty),"width",width,width/2);

        animatorSet.play(alpha)
                .with(rotation)//需要同时执行的动画用with
                .with(w)
                .with(translationX)
                .after(scaleX)//需要执行play之后执行的动画
                .before(scaleY);//需要执行play之前执行的动画

        animator = animatorSet;
        animator.setDuration(6000);
    }

    private void initAnimatorXML() {
        animatorXML = AnimatorInflater.loadAnimator(this, R.animator.beauty_animtor);
        animatorXML.setTarget(img_beauty);
    }

    @Override
    public void initButton() {
        super.initButton();
        //开始动画
        initButton(R.id.btn_start_anim_java, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (animator != null)
                    animator.start();
            }
        });

        //结束动画
        initButton(R.id.btn_start_anim_xml, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (animatorXML != null)
                    animatorXML.start();
            }
        });
    }

    class WrapView {
        private View view;
        private int width;
        private float alpha;

        private float rotation;

        public WrapView(View view) {
            this.view = view;
        }

        public int getWidth() {
            if (view == null) return 0;
            return view.getLayoutParams().width;
        }

        public void setWidth(int w) {
            this.width = w;
            view.getLayoutParams().width = w;
            view.requestLayout();//刷新布局
        }

        public float getAlpha() {
            if (view == null) return 0;
            return view.getAlpha();
        }

        public void setAlpha(float alpha) {
            this.alpha = alpha;
            view.setAlpha(alpha);
            view.requestLayout();
        }

        public float getRotation() {
            if (view == null) return 0;
            return view.getRotation();
        }

        public void setRotation(float rotation) {
            this.rotation = rotation;
            view.setRotation(rotation);
            view.requestLayout();
        }
    }

}
  • 属性动画还可以传入回调,用来监听动画的执行到那一步了。我就不写了,感觉用处不大。谁管你啊,动画跑完就完事儿了。

过渡动画

  • 使用简单哈,首先这个分为5.0版本之前和5.0版本之后,这个是不是真分,我不确定,我看资料这么说,我就这么信了。我使用的时候其实两种用法都不影响哈。

使用

  • 首先呢老规矩定义动画的xml,这次还是在anim文件夹下定义
  • close_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000">
    <translate
        android:fromXDelta="0%p"
        android:toXDelta="100%p"/>
</set>
  • open_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000">
    <translate
        android:fromXDelta="100%p"
        android:toXDelta="0%p"/>
</set>
  • 然后可以在代码中直接使用,一般是使用在跳转代码之后
  • 这里5.0之前,都是使用overridePendingTransition方法,传入动画,跳转的时候就可以看到相应的动画了。
    private void jumpWithPendingAnimation(){
        //Android5.0版本以上
        //5.0以上自带3中专场动画
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
            makeSceneTransitionAnimation();//第一种 看起来是淡入淡出
//            makeTaskLaunchBehind();//alpha的变化,但是感觉用法有问题,乖乖的。
//            custom();//自定义的用法,和5.0以下使用overridePendingTransition方式一样,传入自己的动画。
        }else {
            jump2NextActivity(PendingAnimationActivity.class);
            overridePendingTransition(R.anim.open_enter,R.anim.close_exit);
        }
    }
  • 5.0之后呢,可以使用的方法就灵活多变了。前两种是Android内置的,后一种和老版本一样传入自己定义的动画xml文件。
    private void makeSceneTransitionAnimation(){
        Intent intent = new Intent(this,PendingAnimationActivity.class);
        startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
    }

    private void makeTaskLaunchBehind(){
        Intent intent = new Intent(this,PendingAnimationActivity.class);
        startActivity(intent,ActivityOptions.makeTaskLaunchBehind().toBundle());
    }

    private void custom(){
        Intent intent = new Intent(this,PendingAnimationActivity.class);
        startActivity(intent,ActivityOptions.makeCustomAnimation(this,R.anim.open_enter,R.anim.close_exit).toBundle());
    }
  • 当然,你嫌不够,这里方法有很多,我没有一个一个去看到底是啥,反正很多就完事儿了。


    Android基础之动画(下),第1张
    图片.png
  • 效果,我这里故意将动画时间设置为3000也就是3秒,能清除看到动画的流程哈。

  • 效果动图

  • 这里动图给我转成了jpg,我直接开了个gitee仓库放我的动图行了吧。


    Android基础之动画(下),第2张
    过渡动画.gif
完结撒花。

https://www.xamrdz.com/web/24v1996667.html

相关文章: