随笔【android】动画效果研究(View)【1】介绍了使用Android提供的Animation类实现view/PopupWindow的动画特效。下面讲解下使用java-universal-tween-engine一种动画系统库实现view的某些动画效果。
参考文献:http://code.google.com/p/java-universal-tween-engine/
http://gundumw100.iteye.com/blog/1108830
http://www.java-gaming.org/index.php?topic=25333.0
java-universal-tween-engine是用纯Java写得,可以用来创建平滑的移动系统,比如循环,移动,旋转等,支持swt,swing,android,opengles等。 Tween缓冲大家应该都不陌生,说白了就是从一起始位置逐渐移动到目标位置的过程,这个过程可以是加速移动,也可以是减速移动,这些不同的缓动方式就是 Tween的各种ease。
java-universal-tween-engine的源码可在网页http://code.google.com/p/java-universal-tween-engine/的最后文件链接中获取。
java-universal-tween-engine是通过用户定义动画的轨迹(采用哪种曲线,在X轴还是在Y轴)、运动的终点,运动的时长等等参数实时计算出在运动中某个时间点所要达到的位置,从而当我们拿到这个数据后,就可以将view/PopupWindow确切地显示在那个地点。至于什么时候刷新数据,拿到这个数据后,怎样刷新UI,是代码中自己加以控制的。
源码中一些代码的说明:
(1)定义一个需要运动的物体
public class Particule { private float x, y; public float getX() { return x; } public float getY() { return y; } public void setX(float x) { this.x = x; } public void setY(float y) { this.y = y; } }
(2)Tweenable接口,用于表明运动的返回值和变化值
import aurelienribon.tweenengine.Tweenable; public class TweenableParticule implements Tweenable { // The following lines define the different possible tween types. // It's up to you to define what you need :-) public static final int X = 1; public static final int Y = 2; public static final int XY = 3; // Composition pattern private Particule target; // Constructor public TweenableParticule(Particule particule) { this.target = particule; } // Tweenable implementation //获取当前view/PopupWindow的位置---这个函数需要修改
//view:使用getLeft()/getTop()接口获取x以及y值
@Override public int getTweenValues(int tweenType, float[] returnValues) { switch (tweenType) { case X: returnValues[0] = target.getX(); return 1; case Y: returnValues[0] = target.getY(); return 1; case XY: returnValues[0] = target.getX(); returnValues[1] = target.getY(); return 2; default: assert false; return 0; } }
//拿到新的坐标位置后,怎样更新UI---这个函数需要修改
//view:对于采用AbsoluteLayout布局的view,修改UI的代码如下:
// AbsoluteLayout.LayoutParams view_para = new AbsoluteLayout.LayoutParams(myView.getWidth(),myView.getHeight(),(int)newValues[0],(int)newValue[1]);
// myView.setLayoutParams(view_para);
//AbsoluteLayout参考文献:http://www.cnblogs.com/over140/archive/2010/11/15/1877401.html
//PopupWindow:采用update()更新显示UI @Override public void onTweenUpdated(int tweenType, float[] newValues) { switch (tweenType) { case X: target.setX(newValues[0]); break; case Y: target.setY(newValues[1]); break; case XY: target.setX(newValues[0]); target.setY(newValues[1]); break; default: assert false; break; } } }
(3)TweenManager.update()接口
/** * Updates every tween with the current time. Handles the tween life-cycle * automatically. If a tween is finished, it will be removed from the * manager. * * 每调用一次,就执行一次 */ public final void update() { long currentMillis = System.currentTimeMillis(); for (int i=0; i<tweens.size(); i++) { Tween tween = tweens.get(i); if (tween.isFinished()) { tweens.remove(i); i -= 1; } tween.update(currentMillis); } }
以上是源码中带有的接口,它的缺点是调用它一次,它就更新view一次,所以在Activity中如果要实现view/Popupwindow的动画效果,就必须增加代码,每个多少秒调用这个函数一次,封装性不是很好。
我对这个接口进行了扩展,使用handler,加入定时器,一直更新,从而一旦调用接口update(int delayMillis,int showMillis),就可以看到动画效果:
/** * Updates every tween with the current time. Handles the tween life-cycle * automatically. If a tween is finished, it will be removed from the * manager. * * 启动handler,调用后执行多次 * @param delayMillis, delayMillis ms后开始执行 * @param showMillis,每showMillis ms执行一次 */ public final void update(int delayMillis,int showMillis) { Timer timer =null; timer = new Timer(); //计时任务开始 timer.schedule(new MyTimeTask(),delayMillis,showMillis); } /** * 子函数,用于update(int delayMillis,int showMillis) */ private Handler handler = new Handler() { // 定义处理信息的方法 public void handleMessage(Message msg) { switch (msg.what) { case 1: update(); break; } super.handleMessage(msg); } }; /** * 子函数,用于update(int delayMillis,int showMillis) */ private class MyTimeTask extends TimerTask{ @Override public void run() { Message message = new Message(); message.what = 1; handler.sendMessage(message); } }
另外,java-universal-tween-engine动画库中定义了多种动画曲线轨迹,具体代码在equations文件夹中。