从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 ...
随机推荐
- 实时视频h5
http://www.cnblogs.com/dotfun/p/4286878.html
- [转]9个基于Java的搜索引擎框架
9个基于Java的搜索引擎框架 在这个信息相当繁杂的互联网时代,我们已经学会了如何利用搜索引擎这个强大的利器来找寻目标信息,比如你会在Google上搜索情人节如何讨女朋友欢心,你也会在百度上寻找正规的 ...
- Leetcode 600.不包含连续1的非负整数
不包含连续1的非负整数 给定一个正整数 n,找出小于或等于 n 的非负整数中,其二进制表示不包含 连续的1 的个数. 示例 1: 输入: 5 输出: 5 解释: 下面是带有相应二进制表示的非负整数&l ...
- springmvc和struts2的区别比较
1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...
- 使用hibernate建立mysql连接以及生成映射类和配置文件*.cfg.xml
建立数据库连接 找到window—open perspective—myeclipse database explore空白出右键new注意 driver template 和driver class ...
- 基础概念:Oracle数据库
基础概念:Oracle数据库.实例.用户.表空间.表之间的关系 数据库:Oracle数据库是数据的物理存储.这就包括(数据文件ORA或者DBF.控制文件.联机日志.参数文件).其实Oracle数据库的 ...
- Servlet+Json代码
package com.brmoney.servlet; import java.io.IOException; import java.io.PrintWriter; import java.uti ...
- 【神题】AtCoder 028 C Min Cost Cycle
TO BE DONE 思维题 十分巧妙的转化
- POJ2749 Building roads 【2-sat】
题目 Farmer John's farm has N barns, and there are some cows that live in each barn. The cows like to ...
- jQuery 之 验证表单
简单的东西重复做,做多了之后,才能说熟能生巧. 做好一个精美的页面,固然是好,但是,一个页面除了写好之外,我们更需要的是将其功能完善.比如表单的验证,这只是众多工作之一.然后本次就以jQuery的va ...