Android 动画基础:View 动画

前言

View 动画的作用对象是View,支持4种动画效果,分别是平移动画、缩放动画、旋转动画和透明度动画,对应着Animation 的四个子类:TranslateAnimation、ScaleAnimation、RotateAnimation 和AlphaAnimation。

平移动画

private fun translateAnimEx(btn: Button){
        btn.text="平移动画"
        // xml
        val transAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_translate_ex)
        transAnimation.duration = 3000
        btn.startAnimation(transAnimation)
        // 代码
        val transAnimation=TranslateAnimation(0f,180f,0f,180f)
        transAnimation.duration = 3000
        btn.startAnimation(transAnimation)
    }
anim_translate_ex.xml文件
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="180"
    android:toYDelta="180" />

效果:

缩放动画

private fun scaleAnimEx(btn: Button){
        btn.text="缩放动画"

        // xml
        val scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_scale_ex)
        scaleAnimation.duration = 3000
        btn.startAnimation(scaleAnimation)

        // 代码
        val scaleAnimation=ScaleAnimation(0f,120f,0f,120f,
               50f, 50f)
        scaleAnimation.duration = 3000
        btn.startAnimation(scaleAnimation)
    }
anim_scale_ex.xml
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXScale="0"
    android:toXScale="20"
    android:fromYScale="0"
    android:toYScale="20"
    android:pivotX="50"
    android:pivotY="50"/>

效果:

旋转动画

 private fun rotateAnimEx(btn: Button){
        btn.text="旋转动画"

        // xml
        val rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_rotate_ex)
        rotateAnimation.duration = 3000
        btn.startAnimation(rotateAnimation)

        // 代码
        val rotateAnimation=RotateAnimation(0f,360f,100f,100f)
        rotateAnimation.duration = 3000
        btn.startAnimation(rotateAnimation)
    }
anim_rotate_ex.xml
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:pivotX="100"
    android:pivotY="100"
    android:toDegrees="360" />

效果

透明度动画

private fun alphaAnimEx(btn: Button){
        btn.text="透明动画"
        // xml
        val alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_alpha_ex)
        alphaAnimation.duration=3000
        btn.startAnimation(alphaAnimation)

        // 代码
        val alphaAnimation = AlphaAnimation(0f, 1f)
        alphaAnimation.duration = 3000

        btn.startAnimation(alphaAnimation)
    }
anim_alpha_ex.xml
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="0"
    android:toAlpha="1" />

效果

动画集合

private fun setAnimEx(btn: Button){
        // xml
        val setAnimation = AnimationUtils.loadAnimation(this, R.anim.animation_set)
        setAnimation.duration = 3000
        btn.startAnimation(setAnimation)

        // 代码
        val rotateAnimation=RotateAnimation(0f,360f)
        val transAnimation=TranslateAnimation(0f,180f,0f,180f)

        val setAnimation=AnimationSet(false)
        setAnimation.addAnimation(rotateAnimation)
        setAnimation.addAnimation(transAnimation)

        setAnimation.duration = 350
        setAnimation.fillAfter=true
        setAnimation.interpolator=LinearInterpolator()
        setAnimation.zAdjustment=AnimationSet.ZORDER_NORMAL
        btn.startAnimation(setAnimation)
    }
animation_set.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:interpolator="@android:anim/linear_interpolator"
    android:duration="350"
    android:zAdjustment="normal">

    <translate

        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="100"
        android:toYDelta="100" />

    <rotate
        android:duration="100"
        android:fromDegrees="0"
        android:toDegrees="360" />
</set>

动画 xml 相关属性

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    //动画持续的时间
    android:duration="{int}"
    //动画结束以后View是否停留在结束位置,true表示View停留在结束位置,false则不停留
    android:fillAfter="{true|false}"
    //动画结束以后View是否停留在开始位置,true表示View停留在结束位置,false则不停留
    android:fillBefore="{true|false}"
    // 表示集合中的动画是否和集合共享同一个插值器
    android:shareInterpolator="{true|false}"
    // 重复模式
    android:repeatMode="{restart|reverse}"
    // 延时开始动画
    android:startOffset="{int}"
    // 设置插值器,
    android:interpolator="@{package:}anim/interpolator_resource">

    <rotate
        //旋转开始的角度
        android:fromDegrees="float"
        //旋转的**轴点**的x坐标
        android:pivotX="float"
        // 旋转的**轴点**的y坐标
        android:pivotY="float"
        // 旋转结束的角度
        android:toDegrees="float" />

    <alpha
        //表示透明度的起始值
        android:fromAlpha="float"
        //表示透明度的结束值
        android:toAlpha="float" />
    <scale
        //水平方向缩放的起始值
        android:fromXScale="float"
        //竖直方向缩放的起始值
        android:fromYScale="float"
        //旋转的**轴点**的x坐标
        android:pivotX="float"
        // 旋转的**轴点**的y坐标
        android:pivotY="float"
        //水平方向缩放的结束值
        android:toXScale="float"
        //竖直方向缩放的结束值
        android:toYScale="float" />
    <translate
        //表示x的起始值
        android:fromXDelta="float"
        //表示y的起始值
        android:fromYDelta="float"
        //水平方向缩放的结束值
        android:toXDelta="float"
        // 表示y的结束值
        android:toYDelta="float" />

</set>

自定义动画

只需要继承Animation这个抽象类,然后重写它的initialize 和applyTransformation方法,在initialize方法中做些初始化工作,在applyTransformation 中进行相应的矩阵变换即可,很多时候需要采用Camera来简化矩阵变换的过程。

示例:3D 旋转

// 自定义View 动画
    private fun animatonView() {
        val rotate3DAnimation = Rotate3DAnimation(0f, 360f, 30f, 180f, true, 6f)
        rotate3DAnimation.interpolator = AccelerateDecelerateInterpolator()
        rotate3DAnimation.fillAfter = true
        rotate3DAnimation.duration = 3500
        btn_anim_set.startAnimation(rotate3DAnimation)
    }


class Rotate3DAnimation : Animation {


    private var mFromDegree: Float
    private var mToDegree: Float
    private var mCenterX: Float
    private var mCenterY: Float
    private var mDepthZ: Float
    private var mReverse: Boolean
    private lateinit var mCamera: Camera

    constructor(mFromDegree: Float, mToDegree: Float, mCenterX: Float,mCenterY: Float,   mReverse: Boolean, mDepthZ: Float) : super() {
        this.mFromDegree = mFromDegree
        this.mCenterY = mCenterY
        this.mCenterX = mCenterX
        this.mToDegree = mToDegree
        this.mReverse = mReverse
        this.mDepthZ = mDepthZ
    }


    // 初始化
    override fun initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int) {
        super.initialize(width, height, parentWidth, parentHeight)
        this.mCamera = Camera()
    }

    // 矩阵变化
    override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
        super.applyTransformation(interpolatedTime, t)
        var fromDegree=mFromDegree
        var degree=fromDegree+(mToDegree-mFromDegree)*interpolatedTime

        var centerX=mCenterX
        var centerY=mCenterY

        val  camera=mCamera
        val matrix=t?.matrix
        //将当前的摄像头位置保存下来,以便变换进行完成后恢复成原位
        camera.save()
        // camera.translate,这个方法接受3个参数,分别是x,y,z三个轴的偏移量,我们这里只将z轴进行了偏移
        if (mReverse){
            // z的偏移会越来越大。这就会形成这样一个效果,view从近到远
            camera.translate(0f,0f,mDepthZ*interpolatedTime)
        }else{
            // z的偏移会越来越小。这就会形成这样一个效果,我们的View从一个很远的地方向我们移过来,越来越近,
                // 最终移到了我们的窗口上面
            camera.translate(0f,0f,mDepthZ*(1f-interpolatedTime))
        }
//        View加上旋转效果,在移动的过程中,视图还会移Y轴为中心进行旋转
        camera.rotateY(degree)
//        将我们刚才定义的一系列变换应用到变换矩阵上面,调用完这句之后,我们就可以将camera的位置恢复了,以便下一次再使用
        camera.getMatrix(matrix)
        // camera位置恢复
        camera.restore()
// 以View的中心点为旋转中心,如果不加这两句,就是以(0,0)点为旋转中心
        matrix?.preTranslate(-centerX,-centerY)
        matrix?.postTranslate(centerX,centerY)
    }
}

效果:

VIew 动画原理

每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.contact(transformToApply.getMatrix()),通过矩阵运算完成动画帧。如果动画没有完成,就继续调用invalidate()函数,启动下次绘制来驱动动画,从而完成整个动画的绘制。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值