什么?兔了个兔?吐了还要吐?首先今天,我们自己用android程序实现一个兔年的新年贺卡。下面就是见证美好的时刻,上效果。

好,我们来使用Android动画的知识,来实现这样一个动画效果吧。

需要使用到的知识点

架构设计、Android视图动画、TypeEvaluator、Path、组合模式、代理模式。

思路分析

我们回顾动画的种类,补间动画、帧动画、属性动画以及Android View自带的视图动画。我们今天自己基于属性动画来打造一个山寨版的Android视图动画吧。我们可以从平移动画、缩放动画、旋转动画和透明度动画中抽象出一个基类Action类。我是不会告诉你这个类的命名我是抄的cocos2d的。然后我们扩展Action类,实现这四种动画,再作用在View上。这样就可以让View按我们的动画框架播放动画了。

代码实现

/*** 组合的action可以直接交给view执行。*/
interface Action<A : Action<A>> {fun add(action: A): Afun getAnimator(): Animator<A>fun startAnimation(view: View, duration: Long)
}

抽象一个Action接口,Action还可以添加Action,这里是组合模式的结构。

import android.view.View
import dora.widget.animator.AlphaAnimator
import dora.widget.animator.Animatorclass AlphaAction(val alpha: Float) : Action<AlphaAction> {private var animator = AlphaAnimator()override fun add(action: AlphaAction): AlphaAction {animator.add(action)return this}override fun startAnimation(view: View, duration: Long) {animator.startAnimation(view, duration)}override fun getAnimator(): Animator<AlphaAction> {return animator}operator fun plus(action: AlphaAction) = add(action)init {animator.add(this)}
}

我们以透明度动画为例,在Animator中实现属性动画的逻辑,然后聚合到Action类的实现,通过代理的方式调用我们的动画实现。这里我们重写了+号操作符,这样可以支持两个对象进行相加,这个是Kotlin模仿C++的语法。

import android.view.View
import dora.widget.action.Action
import java.util.*abstract class Animator<A : Action<A>>: Action<A> {protected lateinit var targetView: Viewprotected var actionTree:  MutableList<A> = ArrayList()override fun add(action: A): A {actionTree.add(action)return actionTree[actionTree.size - 1]}override fun startAnimation(view: View, duration: Long) {targetView = view}override fun getAnimator(): Animator<A> {return this}
}

在Animator中,将所有的Action放到一个List集合中保存起来,当我们调用startAnimation()方法,则可以将传入的View拿到,并执行动画。

class AlphaAnimator : Animator<AlphaAction>() {override fun startAnimation(view: View, duration: Long) {super.startAnimation(view, duration)actionTree.add(0, AlphaAction(1.0f))val animator = ObjectAnimator.ofObject(this, ALPHA, AlphaEvaluator(),*actionTree.toTypedArray())animator.duration = durationanimator.start()}fun setAlpha(action: AlphaAction) {val alpha = action.alphatargetView.alpha = alpha}private class AlphaEvaluator : TypeEvaluator<AlphaAction> {override fun evaluate(fraction: Float,startValue: AlphaAction,endValue: AlphaAction): AlphaAction {val action: AlphaActionval startAlpha = startValue.alphaval endAlpha = endValue.alphaaction = if (endAlpha > startAlpha) {AlphaAction(startAlpha + fraction * (endAlpha - startAlpha))} else {AlphaAction(startAlpha - fraction * (startAlpha - endAlpha))}return action}}companion object {private const val ALPHA = "alpha"}override fun getAnimator(): Animator<AlphaAction> {return this}
}

比如AlphaAnimator的实现,我们这里最关键的一行代码就是使用了ObjectAnimator,用它来监听该对象属性的变化。比如这里我们监听alpha属性实际上是监听的setAlpha方法。动画变化的中间值则是通过TypeEvaluator估值器来进行计算估值的。在startAnimation()方法被调用的时候,我们默认在最前面添加了一个默认值。

actionTree.add(0, AlphaAction(1.0f))

我这里只是抛砖引玉,你可以做得更好,比如将初始状态不要写死,让子类去指定或在使用的时候动态指定,这样就会更加的灵活。

abstract class PathAction internal constructor(val x: Float,val y: Float
) : Action<PathAction> {private var animator = PathAnimator()override fun add(action: PathAction): PathAction {animator.add(action)return this}override fun startAnimation(view: View, duration: Long) {animator.startAnimation(view, duration)}override fun getAnimator(): Animator<PathAction> {return animator}operator fun plus(action: PathAction) = add(action)init {animator.add(this)}
}

移动的动画也是类似的逻辑,我们基于Path实现移动动画。

class PathAnimator : Animator<PathAction>() {private val PATH = "path"override fun startAnimation(view: View, duration: Long) {super.startAnimation(view, duration)actionTree.add(0, MoveTo(0f, 0f))val animator = ObjectAnimator.ofObject(this, PATH, PathEvaluator(),*actionTree.toTypedArray())animator.duration = durationanimator.start()}fun setPath(action: MoveTo) {val x = action.xval y = action.ytargetView.translationX = xtargetView.translationY = y}private inner class PathEvaluator : TypeEvaluator<PathAction> {override fun evaluate(fraction: Float, startValue: PathAction, endValue: PathAction): PathAction {var x = 0fvar y = 0fif (endValue is MoveTo) {x = endValue.xy = endValue.y}if (endValue is LineTo) {x = startValue.x + fraction * (endValue.x - startValue.x)y = startValue.y + fraction * (endValue.y - startValue.y)}val ratio = 1 - fractionif (endValue is QuadTo) {x = Math.pow(ratio.toDouble(), 2.0).toFloat() * startValue.x + (2 * fraction * ratio* (endValue).inflectionX) + (Math.pow(endValue.x.toDouble(),2.0).toFloat()* Math.pow(fraction.toDouble(), 2.0).toFloat())y = Math.pow(ratio.toDouble(), 2.0).toFloat() * startValue.y + (2 * fraction * ratio* (endValue).inflectionY) + (Math.pow(endValue.y.toDouble(),2.0).toFloat()* Math.pow(fraction.toDouble(), 2.0).toFloat())}if (endValue is CubicTo) {x = Math.pow(ratio.toDouble(), 3.0).toFloat() * startValue.x + (3 * Math.pow(ratio.toDouble(),2.0).toFloat() * fraction* (endValue).inflectionX1) + (3 * ratio *Math.pow(fraction.toDouble(), 2.0).toFloat()* (endValue).inflectionX2) + Math.pow(fraction.toDouble(), 3.0).toFloat() * endValue.xy = Math.pow(ratio.toDouble(), 3.0).toFloat() * startValue.y + (3 * Math.pow(ratio.toDouble(),2.0).toFloat() * fraction* (endValue).inflectionY1) + (3 * ratio *Math.pow(fraction.toDouble(), 2.0).toFloat()* (endValue).inflectionY2) + Math.pow(fraction.toDouble(), 3.0).toFloat() * endValue.y}return MoveTo(x, y)}}override fun getAnimator(): Animator<PathAction> {return this}
}

曲线运动则牵扯到一些贝瑟尔曲线的知识。 比如二阶的贝瑟尔曲线

class QuadTo(val inflectionX: Float, val inflectionY: Float, x: Float, y: Float) :PathAction(x, y)

和三阶的贝瑟尔曲线

class CubicTo(val inflectionX1: Float,val inflectionX2: Float,val inflectionY1: Float,val inflectionY2: Float,x: Float,y: Float
) : PathAction(x, y)

直线运动则是定义了MoveTo和LineTo两个类。

class MoveTo(x: Float, y: Float) : PathAction(x, y)
class LineTo(x: Float, y: Float) : PathAction(x, y)

调用动画框架API

我们贺卡的动画就是使用了以下的写法,同一类Action可以通过+号操作符进行合并,我们可以同时调用这四类Action进行动画效果的叠加,这样可以让动画效果更加丰富。

(AlphaAction(0.2f) + AlphaAction(1f)).startAnimation(ivRabbit, 2000)(MoveTo(-500f, 100f)+ LineTo(-400f, 80f)+ LineTo(-300f, 50f)+ LineTo(-200f, 100f)+ LineTo(-100f, 80f)+ LineTo(0f, 100f)+ LineTo(100f, 80f)+ LineTo(200f, 50f)+ LineTo(300f, 100f)+ LineTo(400f, 80f)).startAnimation(ivRabbit, 2000)
(RotateAction(0f) + RotateAction(180f)+ RotateAction(360f)) .startAnimation(ivRabbit, 4000)
ScaleAction(2f, 2f).startAnimation(ivRabbit, 8000)
Handler().postDelayed({MoveTo(0f, 0f).startAnimation(ivRabbit, 500)
}, 8000)

兴趣是最好的老师,本文篇幅有限,我们可以通过Android的代码在Android手机上实现各种各样炫酷的效果。跟着哆啦一起玩转Android自定义View吧。

本文转自 [https://juejin.cn/post/7188660825945538619]

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集
二、源码解析合集

三、开源框架合集

欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

Android代码实现新年贺卡动画相关推荐

  1. android 文字跳动动画,Android 仿余额宝数字跳动动画效果完整代码

    Android 仿余额宝数字跳动动画效果完整代码 发布时间:2020-08-24 06:55:30 来源:脚本之家 阅读:120 作者:曾淘 一:想都不用想的,有图有真相,看着爽了,在看下面源码 二: ...

  2. android仿微信红包动画,Android仿打开微信红包动画效果实现代码

    首先看下效果: 实现原理: 准备3张不同角度的图片,通过AnimationDrawable帧动画进行播放即可 代码实现: 1.编写动画xml文件: 根标签为animation-list,其中onesh ...

  3. android 海浪动画,android自定义波浪加载动画的实现代码

    本文实例为大家分享了android自定义波浪加载动画的具体代码,供大家参考,具体内容如下 效果图 1.自定义控件 WaveView package com.example.wh.myapplicati ...

  4. 【iVX 初级工程师培训教程 10篇文拿证】01 了解 iVX 完成新年贺卡

    目录 [iVX 初级工程师培训教程 10篇文拿证]01 了解 iVX 完成新年贺卡 [iVX 初级工程师培训教程 10篇文拿证]02 数值绑定及自适应网站制作 [iVX 初级工程师培训教程 10篇文拿 ...

  5. Android源码解析(一)动画篇-- Animator属性动画系统

    Android源码解析-动画篇 Android源码解析(一)动画篇-- Animator属性动画系统 Android源码解析(二)动画篇-- ObjectAnimator Android在3.0版本中 ...

  6. Android的Activity屏幕切换动画(一)-左右滑动切换

    为什么80%的码农都做不了架构师?>>>    这段时间一直在忙Android的项目,总算抽出点时间休息一下,准备把一些项目用到的Android经验分享一下. 在Android开发过 ...

  7. android view 渐变动画,Android自定义view渐变圆形动画

    本文实例为大家分享了Android自定义view渐变圆形动画的具体代码,供大家参考,具体内容如下 直接上效果图 自定义属性 attrs.xml文件 创建一个类 ProgressRing继承自 view ...

  8. android刷新时的圆形动画_Android自定义加载圈动画效果

    本文实例为大家分享了Android自定义加载圈动画展示的具体代码,供大家参考,具体内容如下 实现如下效果: 该效果图主要有3个动画: 1.旋转动画 2.聚合动画 3.扩散动画 以上3个动画都是通过Va ...

  9. 转 Android的Activity屏幕切换动画(一)-左右滑动切换

    这段时间一直在忙Android的项目,总算抽出点时间休息一下,准备把一些项目用到的Android经验分享一下. 在Android开发过程中,经常会碰到Activity之间的切换效果的问题,下面介绍一下 ...

最新文章

  1. Rocksdb 的优秀代码(三)-- 工业级 线程池实现分享
  2. python3.8自带matlop和numpy吗_Python enlop包_程序模块 - PyPI - Python中文网
  3. maven环境下使用java、scala混合开发spark应用
  4. 禁止微信公众号页面上下滑动
  5. Spring Cloud构建微服务架构:分布式服务跟踪(入门)【Dalston版】
  6. gnss单频软件接收机应用与编程_GNSS/GPS RTK定位 (手机,无人车定位,无人驾驶,因子图优化)...
  7. Unity 4 3 制作一个2D横版射击游戏
  8. php负载均衡慕课网,Nginx实现负载均衡
  9. 「十年老测试」测试员的职场之路
  10. ios plist获取权限
  11. SMART原则是什么
  12. 吉他录音混音教程入门|连这些录音知识都不懂,以后还怎么“混”?| MZD Studios
  13. 全国计算机联合考试广西二级c语言近五年试题,计算机二级c语言试题
  14. python编程else是什么意思_Python 中的 else详解
  15. golang开发:go并发的建议
  16. web前端能做到多少岁?2年能发展到前端技术大牛吗?
  17. grep 忽略大小写、忽略grep命令本身
  18. 光纤连接器的连接方法
  19. oracle 数据泵 network link使用
  20. facebook头像和昵称_如何将昵称添加到您的Facebook个人资料

热门文章

  1. MATLAB技术沙龙之如何批量处理图像的大小
  2. Android-Q显示白平衡
  3. DoraCloud for Proxmox桌面云上启用NVIDIA Tesla P4的vGPU功能
  4. Redis基础进阶--Sentinel 机制与用法(二)
  5. Visual Studio Code修改HTML Snippets插件中默认模板内容
  6. 使用tensorboard时踩的坑
  7. 第二天 05-安装win7系统与远程桌面开启
  8. PLC数据采集有何难点?有什么解决方法?
  9. java如何开发视频软件_使用JAVA编写视频播放器
  10. 鸿蒙系统magic4.0,Magic UI 4.0正式版