从Android动画到贝塞尔曲线

简介:

基础知识:

动画通过连续播放一系列画面,给视觉造成连续变化的图画。很通俗的一种解释。也很好理解。那么我们先来一个案例看看。

动画案例:百度贴吧小熊奔跑

效果:


topic.gif

代码:

    <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/gif_loading1" android:duration="50"></item> <item android:drawable="@drawable/gif_loading2" android:duration="50"></item> <item android:drawable="@drawable/gif_loading3" android:duration="50"></item> <item android:drawable="@drawable/gif_loading4" android:duration="50"></item> <item android:drawable="@drawable/gif_loading5" android:duration="50"></item> <item android:drawable="@drawable/gif_loading6" android:duration="50"></item> <item android:drawable="@drawable/gif_loading7" android:duration="50"></item> </animation-list>
        AnimationDrawable iv_topicAnimation;

        @Override
        protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_topic); ImageView iv_topic = (ImageView) findViewById(R.id.iv_topic); iv_topic.setBackgroundResource(R.drawable.anim_topic); iv_topicAnimation = (AnimationDrawable) iv_topic.getBackground(); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); iv_topicAnimation.start(); } public static void startActiivty(Context context) { context.startActivity(new Intent(context, TopicActivity.class)); }

It's important to note that the start()
method called on the AnimationDrawable cannot be called during the onCreate()
method of your Activity, because the AnimationDrawable is not yet fully attached to the window. If you want to play the animation immediately, without requiring interaction, then you might want to call it from the onWindowFocusChanged() method in your Activity, which will get called when Android brings your window into focus.

可以看到,实现小熊奔跑的效果是非常简单的。你需要理解的是

1.小熊奔跑的效果是有一张张图片交替播放,而动起来的。
2.动画通过连续播放一系列画面,给视觉造成连续变化的图画。


Paste_Image.png

好了,前面只是一个热身,下面才是真正的介绍Android动画了。

Android动画:

  • 逐帧动画(frame-by-frame animation)
  • 补间动画(tweened animation)
  • 属性动画(property animation)

对于逐帧动画和补间动画这里就不打算具体深入,但是你必须要知道的

  • 补间动画,只是改变View的显示效果而已,并不会真正的改变View的属性
  • 补间动画,只作用于View上面

写了个demo来解释一下上面的意思:


tween.gif
     bt_tween.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) { TranslateAnimation animation = new TranslateAnimation(0, 0, 0, 300); animation.setDuration(1000); animation.setFillAfter(true); tv_tween_hello.startAnimation(animation); } }); tv_tween_hello.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context,"hello animation",Toast.LENGTH_SHORT).show(); } });

可以看到其实hello Animation平移之后点击没用了,而点击之前的位置的时候,还是有效的。这也正是我刚才说的

补间动画:只是改变View的显示效果而已,并不会真正的改变View的属性

看到这里,你也知道如果要用补间动画来做一些交互的动画是很蛋疼的。一般做法是:

属性动画

在介绍属性动画前,我们还是先来看一个demo。


property.gif
        protected Person person;
        protected TextView tv_property_info;
        protected Button bt_property;


        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_property); person = new Person(); person.setName("张三"); bt_property = (Button) findViewById(R.id.bt_property); tv_property_info = (TextView) findViewById(R.id.tv_property_info); bt_property.setOnClickListener(this); } @Override public void onClick(View v) { ObjectAnimator objectAnimator = ObjectAnimator.ofInt(person, "age", 1, 100); objectAnimator.addUpdateListener(this); objectAnimator.setDuration(5000); objectAnimator.start(); } @Override public void onAnimationUpdate(ValueAnimator animation) { int values = (int) animation.getAnimatedValue(); person.setAge(values); tv_property_info.setText(person.toString()); }

上面代码模拟了一个Person对象,从0-100岁之间的变化,可能你有点看不懂。我这是在干嘛,但是如果你还记的刚才我说的。属性动画,可以对任何对象属性进行修改,而补间动画,只作用于View上面。我们的demo就是对Person这个对象中属性age不断进行修改。现在,我们假设一个TextView要进行平移或则缩放,或则旋转。只要将对应的属性进行修改,然后重绘。不就可以达到动画的效果了吗?试试吧!


    protected TextView tv_property_info;
        protected Button bt_property;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_property); bt_property = (Button) findViewById(R.id.bt_property); bt_property.setText("View的改变"); tv_property_info = (TextView) findViewById(R.id.tv_property_info); bt_property.setOnClickListener(this); } @Override public void onClick(View v) { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tv_property_info, "TranslationY", 0, 300); objectAnimator.addUpdateListener(this); objectAnimator.setDuration(500); objectAnimator.start(); }

我们来总结一下.当我们调用

 ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tv_property_info, "TranslationY", 0, 300);
 objectAnimator.setDuration(500);

的时候,将初始值和结束值给ObjectAnimator,并且告诉它所需的时长,然后它的内部使用一种时间循环的机制来计算值与值之间的过渡。然后将变化的值返回给我们。然后我们获取这个间隙的值,重绘界面就给视觉造成连续变化的图画。那么内部是怎么计算这个值的呢?

TypeEvaluator
    /**
     * This evaluator can be used to perform type interpolation between <code>float</code> values.
     */
    public class FloatEvaluator implements TypeEvaluator<Number> { /** * This function returns the result of linearly interpolating the start and end values, with * <code>fraction</code> representing the proportion between the start and end values. The * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. * * @param fraction The fraction from the starting to the ending values * @param startValue The start value; should be of type <code>float</code> or * <code>Float</code> * @param endValue The end value; should be of type <code>float</code> or <code>Float</code> * @return A linear interpolation between the start and end values, given the * <code>fraction</code> parameter. */ public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); } }

通过查看源码我们知道,系统内置了一个FloatEvaluator,它通过计算告知动画系统如何从初始值过度到结束值。如果,我们想要自己控制这个时间段的运动轨迹的话,就可以自定义TypeEvaluator来返回轨迹点。下面让我们自己定义一个TypeEvaluator吧!

动画案例:饿了么购物车。

先看效果图片,这样有利于思考.


 

想要实现这个效果,我们必须先定义一个类。来记录小球的x和y的变量。

        public class Point implements Parcelable { public int x; public int y; public Point() {} public Point(int x, int y) { this.x = x; this.y = y; } public Point(Point src) { this.x = src.x; this.y = src.y; } /** * Set the point's x and y coordinates */ public void set(int x, int y) { this.x = x; this.y = y; } }

这个类是android自带的一个类。用来记录小球的运动轨迹点,那么现在我们只需要小球的起始点和终点,然后就可以计算出小球的运动轨迹。那么怎么获取开始点和终点呢?终点的话,是一个定值。而开始点是我们根据点击事件获取的。可以根据

     int position[] = new int[2];
     view.getLocationInWindow(position);

来获取x=position[0];y=position[1]; 现在起始点和终点都已经确定好了,那么我们来计算一下小球运动的轨迹吧。从动画中可以看出来。类似于抛物线。这里我想到了用贝塞尔曲线来做。因为我们只需要确定一个控制点,就可以根据公式算出小球的运动轨迹。


Paste_Image.png

二次方公式
二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:



TrueType字型就运用了以贝兹样条组成的二次贝兹曲线。

有了计算公式,现在还缺一个控制点。那么这个点,该怎么确定呢?

    int pointX = (startPosition.x + endPosition.x) / 2;
    int pointY = (int) (startPosition.y - convertDpToPixel(100, mContext)); Point controllPoint = new Point(pointX, pointY);

我这里确定控制点是,取起始点和终点X的中点,y取开始点网上偏移一个距离。这样就会有一个抛物线的角度了。当然你可以通过http://myst729.github.io/bezier-curve/ 微调下你的控制点。好了,现在我们3个点都已经确定好了,现在就需要计算小球的运动轨迹,然后绘制到Window上去就OK了。

     public class BezierEvaluator implements TypeEvaluator<Point> { private Point controllPoint; public BezierEvaluator(Point controllPoint) { this.controllPoint = controllPoint; } @Override public Point evaluate(float t, Point startValue, Point endValue) { int x = (int) ((1 - t) * (1 - t) * startValue.x + 2 * t * (1 - t) * controllPoint.x + t * t * endValue.x); int y = (int) ((1 - t) * (1 - t) * startValue.y + 2 * t * (1 - t) * controllPoint.y + t * t * endValue.y); return new Point(x, y); } }

上面就是取当小球在时间t的时候,x和y分别是多少,然后去改变View。

      @Override
        public void onAnimationUpdate(ValueAnimator animation) { Point point = (Point) animation.getAnimatedValue(); setX(point.x); setY(point.y); invalidate(); }

记得在动画播放完成后记得移除掉这个小球.

    anim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); ViewGroup viewGroup = (ViewGroup) getParent(); viewGroup.removeView(NXHooldeView.this); } });

那么现在如果叫你实现这种效果,你有思路吗?


也许放弃 才能靠近你 不再见你**
你才会把我记起 时间累积
这盛夏的果实 回忆里寂寞的香气
我要试着离开你 不要再想你
虽然这并不是我本意
你曾说过 会永远爱我
也许承诺 不过因为没把握 别用沉默
再去掩饰甚么 当结果是那么赤裸裸
以为你会说甚么 才会离开我

附上本有所有代码的链接:https://github.com/BelongsH/AnimationExample/tree/master


    本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/7010402.html,如需转载请自行联系原作者





相关文章
|
6月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
140 2
基于Android P,自定义Android开机动画的方法
|
4月前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
9月前
|
Java Android开发 开发者
Android10 修改开发者选项中动画缩放默认值
Android10 修改开发者选项中动画缩放默认值
258 0
|
9月前
|
XML Java Android开发
android的三种动画
android的三种动画
62 0
|
7月前
|
XML Android开发 数据格式
Android 中如何设置activity的启动动画,让它像dialog一样从底部往上出来
在 Android 中实现 Activity 的对话框式过渡动画:从底部滑入与从顶部滑出。需定义两个 XML 动画文件 `activity_slide_in.xml` 和 `activity_slide_out.xml`,分别控制 Activity 的进入与退出动画。使用 `overridePendingTransition` 方法在启动 (`startActivity`) 或结束 (`finish`) Activity 时应用这些动画。为了使前 Activity 保持静止,可定义 `no_animation.xml` 并在启动新 Activity 时仅设置新 Activity 的进入动画。
227 12
|
8月前
|
Android开发 UED
Android Item平移动画
【6月更文挑战第18天】
140 8
|
7月前
|
XML Android开发 UED
Android动画之共享元素动画简单实践
本文介绍Android共享元素动画, 实现两Activity间平滑过渡特定UI元素。通过设置`transitionName`属性和使用`ActivityOptions.makeSceneTransitionAnimation`启动目标Activity实现动画效果。可自定义过渡动画提升体验。
110 0
|
7月前
|
Android开发
android 动画 插值器和估值器
android 动画 插值器和估值器
|
9月前
|
数据库 Android开发
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画

热门文章

最新文章

  • 1
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    Android历史版本与APK文件结构
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 4
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 1
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    21
  • 2
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    37
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    107
  • 4
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    39
  • 5
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    54
  • 6
    Android历史版本与APK文件结构
    145
  • 7
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    46
  • 8
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    39
  • 9
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    66
  • 10
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    47