属性动画实现旋转入场效果

属性动画和硬件加速

日常杂谈
06月07日

首先,我感觉这部分内容真的挺无聊的,没有什么让人新奇的感觉。不过为了博客的整体性,我还是想随便整理一下相关的知识和内容。

一如既往,聊聊我的日常生活,最近可能比较忙,所以可能没有那么多大段的时间来写博客。只能用那种零碎的时间来一点一点拼凑。虽然时间少不影响我追番,毕竟这个是我最大的爱好,也是我最大的解压和放松娱乐的方式,这点我不否认和排斥。

今天,停更一周的《我推的孩子》终于又要更新了,感觉非常非常的开心,说实话上一话的神结尾真的是震撼到我了,瞬间的场景变化,人物气场和表情的变化,女配光是通过肢体的不协调就看出了星野爱的未成年性体验经历。综上,期待今天晚上的番剧更新吧~

之前有人在我的博客下,说我的博客废话太多,然后另外一个人回复他说,他倒是挺喜欢我的这种博客方式的。然后那人就在那里阴阳怪气起来了,说什么你是懂反讽的。说实话,我挺惊讶的,没想到程序员圈子里还有这种货色,你是工作不饱和吗?来这里闲着还不如去多学习学习!


06月08日

随着工作强度的增加和要写的东西的复杂性增加,日常杂谈的篇幅可能要会分为好几部分了。正经人谁写日记啊,对,我就是那个不正经人。

前言

其实我感觉这部分的内容挺无趣的,不过我会尽量用比较有趣的案例来讲述吧。想了很久,到底用什么方式来讲述相关的内容会比较有趣,而不是单纯的在读教案。这点其实困惑了我挺久的,非常久,非常久,大概有10分钟左右吧,一直在想一直在想。然后我决定搞一个骚操作,弄个相对来说比较有挑战性的效果:变速旋转入场。

正文

其实想实现同一个动画效果存在非常非常多的方式,唯一的区别就是具体的实现是简单还是困难,性能高还是性能低而已。

首先,我们定义一个视图,在视图的正中间显示一张图片。

在我们的XML布局中定义我们所需要显示的图片信息,并将其居中显示:


<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_view"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CiruyMainActivity">
    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/targetView"
        android:layout_margin="30dp"
        android:src="@drawable/avatar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
androidx.appcompat.widget.LinearLayoutCompat>

我们先来看一下怎么实现变速旋转入场,这里介绍两种可以实现对应效果的方法:

一、使用官方的动画API
因为我们需要实现的动画效果,实际上非常简单,单纯调用官方API就已经足够能够实现我们的需要。

在Activity中我们获取到XML文件中显示的视图,对其进行动画效果:

val targetView = findViewById<FlipView>(R.id.targetView)
        //旋转缩放入场
        targetView.animate()
            .rotation(360f)//原地旋转360度
            .scaleXBy(-0.5f)//缩小到原来的一半大小
            .scaleYBy(-0.5f)//缩小到原来的一半大小
            .setDuration(1000)//设置动画的时长
            .setStartDelay(1500)//设置动画开始的等待时间
            .start()	

通过如上代码,我们就能实现视图的旋转和同步缩放效果。

二、通过自定义属性动画的方式来实现对应的效果

这个相对于前面的方式可能会稍微复杂一些,但是优点在于这种方式更加灵活,当然也有缺点,这个在之后会进行提及。

这个方式主要分为如下几个步骤:

  1. 定义一个自定义视图,在自定义视图中定义一个参数,然后我们视图绘制就根据这个参数来进行绘制。

这里使用了kotlin中的重载操作符,让后续进行进度计算时,代码更加清晰。没办法,代码强迫症,不太喜欢让代码变得太过于复杂。

class ObjectAnimatorView(context: Context, attributeSet: AttributeSet) :
    View(context, attributeSet) {
    private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    var mViewParam = ViewParam(0f, 1f)
    set(value) {
        field = value
        invalidate()//在接收到属性更新的时候,让视图在下次刷新页面的时候刷新状态
    }
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //获取到图片文件,根据具体的scale值来动态决定到底获取多大的视图信息
        val bitmap = R.drawable.avatar.getBitmap(context, (width*mViewParam.scale).toInt())
        val bWidth = bitmap.width//图片宽度
        val bHeight = bitmap.height//图片高度
        canvas.save()
        //旋转图片
        canvas.translate(width/2f,height/2f)
        canvas.rotate(mViewParam.rotate)
        canvas.translate(-width/2f,-height/2f)
        canvas.drawBitmap(bitmap, width / 2f - bWidth / 2, height / 2f - bHeight / 2, mPaint)
        canvas.restore()
    }

}
//自定属性存储bean,重载操作符
data class ViewParam(val rotate: Float, val scale: Float){
    operator fun plus(other: ViewParam) = ViewParam(rotate+other.rotate,scale+other.scale)
    operator fun minus(other: ViewParam) = ViewParam(rotate-other.rotate,scale-other.scale)
    operator fun times(time:Float) = ViewParam(rotate*time,scale*time)
}
  1. 在Activity中获取到这个视图,自定义一个ObjectAnimator,启动动画。
val targetView: ObjectAnimatorView = findViewById<ObjectAnimatorView>(R.id.targetView)
        ObjectAnimator.ofObject(
            targetView,
            "mViewParam",
            typeEvaluator,
            ViewParam(360f, 0.5f)//原地旋转360度,同时缩小宽高到原来的一半
        ).apply { startDelay = 1000
        duration = 1000}
            .start()
//自定义每一个时刻的动画播放进度
 val typeEvaluator:TypeEvaluator<ViewParam> =
        TypeEvaluator<ViewParam> { fraction, startValue, endValue -> startValue + (endValue-startValue)*fraction }

另外再谈谈硬件加速吧,什么是硬件加速?设备中其实有一个叫GPU的好东西,它相对于CPU更擅长处理简单的动画变换效果。而将这部分所谓的简单的动画效果交给GPU来处理,

开启视图硬件加速的方式:在视图初始化代码中添加如下方法,

    init {
        setLayerType(LAYER_TYPE_HARDWARE, null)
    }

另外还需要再动画方法里面添加离屏缓存,即withLayer方法:

//旋转缩放入场
targetView.animate()
    .rotation(360f)
    .scaleXBy(-0.5f)
    .scaleYBy(-0.5f)
    .setDuration(1000)
    .setStartDelay(1500)
    .withLayer()
    .start()

注意:Android硬件加速只对如上这样官方定义的简单效果有性能提升效果,具体哪些有优化效果请参考官方文档。对于自定义的动画效果,反而会影响性能。

你可能感兴趣的:(动画,android)