基础知识:

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

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

效果:

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

从Android动画到贝塞尔曲线的更多相关文章

  1. CSS总结六:动画(一)ransition:过渡、animation:动画、贝塞尔曲线、step值的应用

    transition-property transition-duration transition-timing-function transition-delay animation-name a ...

  2. Android自定义View——贝塞尔曲线实现水波纹效果

    我们使用到的是Path类的quadTo(x1, y1, x2, y2)方法,属于二阶贝塞尔曲线,使用一张图来展示二阶贝塞尔曲线,这里的(x1,y1)是控制点,(x2,y2)是终止点,起始点默认是Pat ...

  3. Android -- 贝塞尔曲线公式的推导

    1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...

  4. Android -- 贝塞尔曲线公式的推导和简单使用

    1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...

  5. Android中贝塞尔曲线的绘制方法

    贝塞尔曲线,很多人可能不太了解,什么叫做贝塞尔曲线呢?这里先做一下简单介绍:贝塞尔曲线也可以叫做贝济埃曲线或者贝兹曲线,它由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋.一般的矢量图形软件常 ...

  6. 贝塞尔曲线与CSS3动画、SVG和canvas的应用

    简介 贝塞尔曲线是可以做出很多复杂的效果来的,比如弹跳球的复杂动画效果,首先加速下降,停止,然后弹起时逐渐减速的效果. 使用贝塞尔曲线常用的两个网址如下: 缓动函数:http://www.xuanfe ...

  7. 贝塞尔曲线(cubic bezier)

    对于css3的Transitions,网上很多介绍,相信大家都比较了解,这里用最简单的方式介绍下: transition语法:transition:<transition-property> ...

  8. OpenGL 实践之贝塞尔曲线绘制

    说到贝塞尔曲线,大家肯定都不陌生,网上有很多关于介绍和理解贝塞尔曲线的优秀文章和动态图. 以下两个是比较经典的动图了. 二阶贝塞尔曲线: 三阶贝塞尔曲线: 由于在工作中经常要和贝塞尔曲线打交道,所以简 ...

  9. Android 利用二次贝塞尔曲线模仿购物车加入物品抛物线动画

    Android 利用二次贝塞尔曲线模仿购物车加入物品抛物线动画 0.首先.先给出一张效果gif图. 1.贝塞尔曲线原理及相关公式參考:http://www.jianshu.com/p/c0d7ad79 ...

随机推荐

  1. 36、imageview的坑

    当频繁设置imageview的背景图片时,用: imageviewChooseStaff.setImageResource(R.drawable.default_head_pic); 而不是 imag ...

  2. Bug的类型

    美国计算机科学家.图灵奖获得者詹姆斯·尼古拉·格雷(Jim Gray),在他的著名的论文“Why do computers stop and what can be done about it?”中首 ...

  3. Python-S9-Day114——Flask开始实战

    01 今日内容概要 02 课前分享 03 内容回顾 04 路飞学城表结构(一) 05 路飞学城表结构(二) 06 路飞学城立即支付思路 07 今日作业 08 初识Flask 09 werkzug 10 ...

  4. iOS开发UI篇—自定义layer

    一.第一种方式 1.简单说明 以前想要在view中画东西,需要自定义view,创建一个类与之关联,让这个类继承自UIView,然后重写它的DrawRect:方法,然后在该方法中画图. 绘制图形的步骤: ...

  5. [canvas入坑1]canvas 画布拖拽效果

    查看效果请到 http://philippica.github.io/  点击drag 和上一篇画图很像,所以有些部分做了省略 当鼠标按下时保存当前画布上的内容到ppImgData中,并且记录下初始点 ...

  6. ceoi2017 Building Bridges(build)

    Building Bridges(build) 题目描述 A wide river has nn pillars of possibly different heights standing out ...

  7. 【自己D自己】WC2019总结

    好吧写着写着写成自黑文了. 这是我时隔一个月写的,寒假非常自闭,肝童年游戏赛尔号来着…… 没玩过的无视 作为一个 $BJ$ 蒟蒻,第一次飞到广州二中这么远的地方(我没出过国,去广州算是很远的一次了). ...

  8. EntityFramework4.1 MODEL代码生成器 database first

    原文发布时间为:2011-04-02 -- 来源于本人的百度文章 [由搬家工具导入] Generating EF Code First model classes from an existing d ...

  9. css3 ani-2-trans, any to transform!!! css3 animation jingsui! Hover

    http://www.daqianduan.com/example?pid=2959 animation, transition, transform or ani 2 trans

  10. HttpHandler,HttpApplication, HttpModule

    选择HttpHandler还是HttpModule? HttpHandler和HttpModule之间有什么差别 之所以有这个疑问,是因为在这二类对象中都可以访问Request, Response对象 ...