从Android动画到贝塞尔曲线
基础知识:
动画通过连续播放一系列画面,给视觉造成连续变化的图画。很通俗的一种解释。也很好理解。那么我们先来一个案例看看。
动画案例:百度贴吧小熊奔跑
效果:
代码:
<?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.动画通过连续播放一系列画面,给视觉造成连续变化的图画。
好了,前面只是一个热身,下面才是真正的介绍Android动画了。
Android动画:
- 逐帧动画(frame-by-frame animation)
- 补间动画(tweened animation)
- 属性动画(property animation)
对于逐帧动画和补间动画这里就不打算具体深入,但是你必须要知道的
- 补间动画,只是改变View的显示效果而已,并不会真正的改变View的属性
- 补间动画,只作用于View上面
写了个demo来解释一下上面的意思:
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的属性
看到这里,你也知道如果要用补间动画来做一些交互的动画是很蛋疼的。一般做法是:
- 预先在动画结束的地方设置一个不可见的View,然后动画结束之后,让其显示。这样就可以处理事件。
- 利用https://github.com/JakeWharton/NineOldAndroids
属性动画
在介绍属性动画前,我们还是先来看一个demo。
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]; 现在起始点和终点都已经确定好了,那么我们来计算一下小球运动的轨迹吧。从动画中可以看出来。类似于抛物线。这里我想到了用贝塞尔曲线来做。因为我们只需要确定一个控制点,就可以根据公式算出小球的运动轨迹。
二次方公式
二次方贝兹曲线的路径由给定点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动画到贝塞尔曲线的更多相关文章
- CSS总结六:动画(一)ransition:过渡、animation:动画、贝塞尔曲线、step值的应用
transition-property transition-duration transition-timing-function transition-delay animation-name a ...
- Android自定义View——贝塞尔曲线实现水波纹效果
我们使用到的是Path类的quadTo(x1, y1, x2, y2)方法,属于二阶贝塞尔曲线,使用一张图来展示二阶贝塞尔曲线,这里的(x1,y1)是控制点,(x2,y2)是终止点,起始点默认是Pat ...
- Android -- 贝塞尔曲线公式的推导
1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...
- Android -- 贝塞尔曲线公式的推导和简单使用
1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...
- Android中贝塞尔曲线的绘制方法
贝塞尔曲线,很多人可能不太了解,什么叫做贝塞尔曲线呢?这里先做一下简单介绍:贝塞尔曲线也可以叫做贝济埃曲线或者贝兹曲线,它由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋.一般的矢量图形软件常 ...
- 贝塞尔曲线与CSS3动画、SVG和canvas的应用
简介 贝塞尔曲线是可以做出很多复杂的效果来的,比如弹跳球的复杂动画效果,首先加速下降,停止,然后弹起时逐渐减速的效果. 使用贝塞尔曲线常用的两个网址如下: 缓动函数:http://www.xuanfe ...
- 贝塞尔曲线(cubic bezier)
对于css3的Transitions,网上很多介绍,相信大家都比较了解,这里用最简单的方式介绍下: transition语法:transition:<transition-property> ...
- OpenGL 实践之贝塞尔曲线绘制
说到贝塞尔曲线,大家肯定都不陌生,网上有很多关于介绍和理解贝塞尔曲线的优秀文章和动态图. 以下两个是比较经典的动图了. 二阶贝塞尔曲线: 三阶贝塞尔曲线: 由于在工作中经常要和贝塞尔曲线打交道,所以简 ...
- Android 利用二次贝塞尔曲线模仿购物车加入物品抛物线动画
Android 利用二次贝塞尔曲线模仿购物车加入物品抛物线动画 0.首先.先给出一张效果gif图. 1.贝塞尔曲线原理及相关公式參考:http://www.jianshu.com/p/c0d7ad79 ...
随机推荐
- C 语言 习题 1-10
练习 1-10 编写一个将输入复制到输出的程序,并将其中的制表符替换为\t,把回退符替换为\b,把反斜杠替按为\\.这样可以将制表符和回退符以可见的方式显示出来. #include<stdio. ...
- TortoiseSVN 同时检索多人的提交日志记录(如图操作)
- SDRAM学习(二)之初始化
目录 1.SDRAM初始化的内容(结合英文数据手册) 2.SDRAM初始化的时序 3.代码的编写 4.modesim的仿真 SDRAM初始化的内容 SDRAMs must be powered up ...
- Linux下测试SSD固态硬盘写入速度
最近买了一个256GB的SSD固态硬盘,想测试一下写入速度,于是如下操作. 部分代码: gettimeofday(&start, NULL); int fd = open("test ...
- Python的网络编程socket模块
(1)利用socket进行简单的链接 Python里面的socket支持UDP.TCP.以及进程间的通信,socket可以把我们想要发送的东西封装起来,发送过去,然后反解成原来的样子,事实上网路通信可 ...
- HDU3232 Crossing Rivers 数学期望问题
Crossing Rivers ...
- CodeForces Round #515 DIv.3 F. Yet another 2D Walking
http://codeforces.com/contest/1066/problem/F Maksim walks on a Cartesian plane. Initially, he stands ...
- 基于jQuery的插件
jQuery Validation 验证框架 jQuery Form Ajax表单插件 jQuery UI插件 Easy UI
- 编程风格---代码中doxygen方式的注释写法
代码中doxygen方式的注释写法: 1. 模块定义(单独显示一页) /* * @defgroup 模块名 模块的说明文字 * @{ */ … 定义的内容 … /** @} */ // 模块结尾 2. ...
- 卷积神经网络用语句子分类---Convolutional Neural Networks for Sentence Classification 学习笔记
读了一篇文章,用到卷积神经网络的方法来进行文本分类,故写下一点自己的学习笔记: 本文在事先进行单词向量的学习的基础上,利用卷积神经网络(CNN)进行句子分类,然后通过微调学习任务特定的向量,提高性能. ...