安卓:自定义动画视图

21

编辑2:新的官方培训指南

开发者网站发布了一个与UI相关的培训指南,以下是目录:

  • 动画概述
  • 属性动画概述
  • 动画绘图
  • 使用动画显示或隐藏视图
  • 使用动画移动视图
  • 使用甩动画移动视图
  • 使用缩放动画放大视图
  • 使用弹簧物理学动画移动
  • 自动动画布局更新
  • 使用转换动画动画布局更改
  • 创建自定义转换动画
  • 使用动画启动活动

如果您对其中任何内容感兴趣,这是链接: https://developer.android.com/training/animation/


编辑:答案总结

我发现在Android中有5种动画方式:

  1. 使用属性动画来平滑地更改旋转透明度缩放等视图的属性

  2. 帧动画AnimationDrawable):快速更改图片,使其看起来像是动画。

  3. 使用矢量图形VectorDrawable)设计图像,并通过AnimatedVectorDrawable随时间进行编辑以动画化它们。

  4. 覆盖View上的onDraw()并通过在画布上绘制来执行自定义绘制

  5. 使用Lottie,它可以重现来自After Effects的动画。许多动画可在LottieFiles上找到。

然而,Android还提供了一些内置工具,例如Scenes(它允许您在共享Views的多个布局之间动画转换),Shared elements(它使您可以在一个Activity中将View传递到另一个Activity)等。

这些功能中的许多(如果不是全部)都是在API 21中添加的,单击此处了解更多信息。

以下是一些有关动画的有趣文章/博客:

最后,还有一些有趣的工具:

  • GitHub上有一款Mac工具,可以录制Android屏幕。

  • 在线视频转GIF动画的转换器。


注意

我知道Android提供了一些转换,例如缩放透明度旋转平移等。

示例

有两个示例我想看看并进行比较。

1 - 自定义视图动画

例如,倒满一杯水绘制路径

2 - 复杂的视图动画

例如,StackExchange App for Android,登录屏幕动画(找不到视频,也没有检查在iOS中是否表现相同)。

问题

对于第一个示例,我想不出其他方法,只能播放GIF或在短时间内手动更改图像。

我不认为这是情况,所以我想问,(1)你知道它是如何实现的吗?

关于第二个例子,我只有一个想法,那就是设置一个Path,并通过某种方式在animate()之后移动View(2)这可能吗?
除了上述提到的方法,(3)你知道其他播放动画的技术吗?(例如 场景转换 - 在答案中提到-)
请分享!谢谢。

你考虑过使用动态矢量图形吗? - azizbekian
@azizbekian 我之前不知道这个,但看起来使用起来非常繁琐。我在矢量可绘制图形指南网页上查看了示例。我认为它适合更简单的图像。您认为能否实现我提供的图像的相同效果? - JonZarate
理论上你是可以的。但是矢量图主要用于图标。如果SVG中的路径相对简单,渲染它不会花费太多时间。在这里,您可以查看更多详细信息以了解如何实现它。 - azizbekian
如果您提供一个类似于水杯的例子,并回答如何获得像SO App登录那样的动画,我会将其标记为最佳答案。 - JonZarate
无法理解 SO 应用程序登录时的动画。在我的手机上,它是最新版本,只有带有进度条的闪屏界面。 - azizbekian
@azizbekian 你必须注销才能看到它。 - JonZarate
4个回答

10
"

装满杯子的水

动画可以直接使用帧动画实现,即连续更换图片。你可以在这里查看一篇很好的博客文章,描述了如何实现这种动画,基本上与你提到的“装满杯子的水”相同:

enter image description here

另外一个动画乍一看可能会有些难度。

enter image description here

但是打开“显示布局边界”后,你会发现其中并没有什么魔法。基本上这只是一个翻译动画,将一个视图从一个位置平移至另一个位置。对于这个动画,难点在于实现查找翻译坐标的算法。之后,通过场景过渡动画,动画实现只需要几行代码。

"
// assuming at this step all the views are at the initial position at x0, y0
TransitionManager.beginDelayedTransition(rootLayout);
// here set view coordinates to x1, y1 - the final position

转场框架将为您完成其余工作。它将找到增量并为您执行动画。在这里,您将找到来自Lucas Rocha的精彩文章。


1
在这个答案上点个赞,我写了一个更复杂的“复杂视图动画”示例,其中有一堆ViewPropertyAnimator从(半随机)屏幕外开始,并以translationX(0f)和translationY(0f)结束。 - Kasra Rahjerdi
太棒了,我知道类似AnimationDrawable的东西存在,但我没想到它是如此常见和广泛使用的技术。Scene转换也是一个很好的贡献,我看过一些相关视频,但出于某种原因我没有考虑到它。我认为你只是错过了一些关于AnimatedVectorDrawables的信息,这些信息已经被David Medenjak的回答涵盖了。许多技巧,非常有用的信息。 - JonZarate
在接受最佳答案之前,我想再等几天,以防有人想补充一些遗漏的内容。不过没关系,你的回答已经解决了我的问题。另外,你能分享一下用于录制屏幕并制作 GIF 的软件吗? - JonZarate
Azizbekian,你能回答我之前的问题吗? - JonZarate
@JonZarate,嗨!没有注意到你的问题。当然可以。有一个不错的工具,可以轻松地捕捉屏幕。它可以捕捉视频,然后我在网上将其转换并调整大小为gif。这是链接 - azizbekian

6

你知道其他播放动画的技巧吗?

在Android中,您基本上有三种实现动画的方法:

  • 通过使用view.startAnimation(...)仅对视图进行动画处理(缩放,alpha,旋转等)
  • 对Drawable进行动画处理(根据Drawable的不同,这可以是任何内容,从动态矢量绘图到帧动画frame animations
  • 进行自定义绘制和动画处理

显然,仅通过框架方法对视图进行动画处理比创建一些可绘制的动画容易,而创建一些可绘制的动画(xml)比进行自定义绘制容易。

您提到了几天前刚出来的Lottie。我们将看到它的表现如何,但它看起来非常有前途。在幕后,Lottie将解析JSON并使用CanvasPath(上面第三个项目符号)进行一些自定义绘制
如果您能够使用After Effects,这可能是复杂动画的“最简单”解决方案(并且跨平台!)

人们也开始分享动画,你可以在这里找到它们:
http://www.lottiefiles.com/

你知道这是怎么做的吗?

这个(1)视频看起来像是他们进行了一些定制绘图。

  • 为水绘制和填充Path,在它向上动画时用一些波浪动画顶部,并撒上一些白点。
  • 绘制玻璃的形状。

这将涉及创建自定义视图和/或可绘制对象,并覆盖onDraw(Canvas)Path.lineTo以及一些弧线、立方体或二次曲线即可...我既不是设计师也不是矢量专家 :)

我认为这不容易使用动态矢量可绘制对象实现,但您可以通过应用路径变形动画来完成它。(另外,如果我没记错的话,动态矢量可绘制对象仅支持21+)

这个(2)视频仅仅是通过动画路径和抖动旗帜来实现。可以使用AnimatedVectorDrawables(如this blog所示)裁剪路径的开头/结尾,或者通过自定义绘图(从而也支持pre lolipop设备)来动画化路径,例如使用PathMeasure.getSegment()来连续地动画化路径。

正如azizbekians answer所指出的那样,这个(3)动画是第一种提到的类型,只是对视图进行动画(移动和缩放)。


关于第二个例子,我只想到了一种方法,就是设置路径并通过某种方式在animate()之后将View相应地移动。 (2)这种方法可行吗?
沿着路径移动视图显然是可能的,但是视图会移动,你仍然需要找到一种方法来绘制沿着它的路径,如上所述。

非常有用的信息,谢谢。关于AnimatedVectorDrawable最低API的问题,我认为它可以在API 14(4.0)中使用一些Android支持库。请查看链接以获取更多信息。昨天已经点赞了。 - JonZarate

1
我想推荐一个我一段时间前写的库(最近发布),它允许您创建自定义视图并为其添加动画。
您可以在这里找到它,以及一个非常简单的演示。 虽然我的演示并不那么令人印象深刻,但它们展示了库的强大之处,最重要的是如何使用它。
它与Android的TimeInterpolator及其任何子类(以及自定义类)一起工作。
动画完全使用Canvas绘制,唯一的区别是您可以获得一个动画值,该值根据时间作为TimeInterpolator函数而变化。
您可以向视图添加任意数量的动画,独立地控制它们。除此之外,您还可以绘制非动画内容。有一个专门的方法用于此(onDrawStatics)。

目前正在开发一款新版本,基于相同的想法,但实现得更好。 - user3705007

-2
对于您的自定义视图,我建议您确定要在其上执行动画的属性。
例如,如果是一个ClockView,在OnDraw()中设置paint、stroke等后,
您可能需要异步方法/Runnable,以在后台连续更新属性,从而产生逐帧动画,但实际上并不是帧动画,因为您只是在动画视图的属性(向左旋转),而不是整个帧。
有许多例子,通过简单地搜索即可自己实现。

我认为那一点也不优雅。 - JonZarate
这就是动画的制作方式,伙计,一切都只是更新。 - Nandhu
这可能是Android的做法,但不是专业应用程序开发的方式。更不用说,您的“AsyncMethods/Runnables”方法已经过度使用,因为Android已经提供了动画。简而言之,您建议覆盖“onDraw”,然后呢?每50毫秒逐像素绘制水杯动画?您知道需要多少工作量吗?如果您对此非常确定,请继续并展示一个例子... - JonZarate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接