GWT 中流畅的类 jQuery 动画
Posted
技术标签:
【中文标题】GWT 中流畅的类 jQuery 动画【英文标题】:Smooth jQuery-like animation in GWT 【发布时间】:2012-12-24 09:52:49 【问题描述】:我正在玩 GWT 的动画课程作为练习。我的目标不是为 GWT 创建另一个小部件/动画库。另外,我很清楚有很多图书馆可以做到这一点。 我想做的是学习如何做到这一点,而不是如何使用某些库。这仅用于教育目的......
话虽如此,我已经实现了一个简单的类,它在一些小部件上执行 4 种不同的动画:淡入、淡出、滑入和滑出(遵循 jQuery 的动画模型)。请参阅下面的代码了解我是如何实现它的。
现场演示: http://www.rodrigo-silveira.com/gwt-custom-animation/
我的问题:如何在触发另一个动画时顺利[成功地]停止一个动画,并在旧动画停止的地方继续当前动画?
例如,如果在调用 slideOut() 时,slideIn() 已完成一半,我如何才能从小部件的自然高度 50% 开始滑出?我尝试保留一个始终跟踪当前进度的成员变量,以便我可以在新动画中使用它,但似乎无法正确处理。有什么想法吗?
import com.google.gwt.animation.client.Animation;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Element;
public class RokkoAnim extends Animation
private Element element;
private int currentOp;
private final static int FADE_OUT = 0;
private final static int FADE_IN = 1;
private final static int SLIDE_IN = 2;
private final static int SLIDE_OUT = 3;
public RokkoAnim(Element element)
this.element = element;
public void fadeOut(int durationMilli)
cancel();
currentOp = RokkoAnim.FADE_OUT;
run(durationMilli);
public void fadeIn(int durationMilli)
cancel();
currentOp = RokkoAnim.FADE_IN;
run(durationMilli);
public void slideIn(int durationMilli)
cancel();
currentOp = RokkoAnim.SLIDE_IN;
run(durationMilli);
public void slideOut(int durationMilli)
cancel();
currentOp = RokkoAnim.SLIDE_OUT;
run(durationMilli);
@Override
protected void onUpdate(double progress)
switch (currentOp)
case RokkoAnim.FADE_IN:
doFadeIn(progress);
break;
case RokkoAnim.FADE_OUT:
doFadeOut(progress);
break;
case RokkoAnim.SLIDE_IN:
doSlideIn(progress);
break;
case RokkoAnim.SLIDE_OUT:
doSlideOut(progress);
break;
private void doFadeOut(double progress)
element.getStyle().setOpacity(1.0d - progress);
private void doFadeIn(double progress)
element.getStyle().setOpacity(progress);
private void doSlideIn(double progress)
double height = element.getScrollHeight();
element.getStyle().setHeight(height * (1.0d - progress), Unit.PX);
private void doSlideOut(double progress)
// Hard coded value. How can I find out what
// the element's max natural height is if it's
// currently set to height: 0 ?
element.getStyle().setHeight(200 * progress, Unit.PX);
用法
// 1. Get some widget
FlowPanel div = new FlowPanel();
// 2. Instantiate the animation, passing the widget
RokkoAnim anim = new RokkoAnim(div.getElement());
// 3. Perform the animation
// >> inside mouseover event of some widget:
anim.fadeIn(1500);
// >> inside mouseout event of some widget:
anim.fadeOut(1500);
【问题讨论】:
你能分享你的代码,你从哪里开始你的动画? @Sam 刚刚编辑过帖子。请参阅用法示例。 不应该是:anim.fadeIn(1500)
而不是 div.fadeIn(1500)
(fadeOut
也是如此)?
哎呀...好眼力。谢谢。
【参考方案1】:
需要根据当前值更新不透明度(相当于+=
或-=
赋值):
private void doFadeOut(double progress)
double opacity = element.getStyle().getOpacity();
element.getStyle().setOpacity(opacity - 1.0d - progress);
private void doFadeIn(double progress)
double opacity = element.getStyle().getOpacity();
element.getStyle().setOpacity(opacity + progress);
【讨论】:
请注意,如此多地更改 CSS 值会导致浏览器性能下降。如果可以,您应该使用 CSS 转换,例如类似transition: opacity .25s ease-in-out;
,只需在doFadeIn
和doFadeOut
中设置或取消设置一个类。【参考方案2】:
-
在动画类中添加一个实例方法 bool cancelled
只有在没有取消的情况下才运行动画。
添加方法cancelAnnimation,每次新动画开始时调用该方法。
private bool canceled = false;
public void cancelAnnimation()
canceled = true;
private void doFadeOut(double progress)
if(!canceled)
element.getStyle().setOpacity(1.0d - progress);
... etc.
这就是你可以停止动画的方式。但是现在,您需要从当前点开始新的动画。所以最好是再次修改类。
-
添加两个实例变量 currentProgress 和 offset (double)
向构造函数添加双偏移
取消动画时返回 currentProgress。
以第一个动画的偏移量开始新动画。
private bool canceled = false;
private double currentProgress = 0;
private double offset = 0;
public RokkoAnim(Element element, double offset)
this.element = element;
this.offset = offset;
public double cancelAnimation()
canceled = true;
return currentProgress;
private void doFadeOut(double progress)
if(!canceled && ((progress + offset) <= 1))
element.getStyle().setOpacity(1.0d - (progress+offset));
currentProgress = progress+offset;
... etc.
double offset = anim1.cancelAnimation();
RokkoAnim anim2 = new RokkoAnim(div.getElement(), offset);
【讨论】:
为什么将因子设置为-1?这个值不起作用。如果一个小部件正在淡入...它从不透明度 = 0 开始,当它的不透明度为 0.7(70% 可见)时,小部件开始淡出。所以我们将因子设置为 -1 并停止淡入。因此,fadeOut 应该以 opacity = 0.7 开始(而不是 1.0,就像它目前所做的那样),并从那里降低不透明度。根据您的建议,首次调用 doFadeOut 时(进程 ~= 0.1),不透明度应不超过 0.7。但是您的数学将不透明度设置为 (1 - (-1 * 0.1)) = 1.1,这是错误的。 你是对的,我犯了一个错误。我以为你想回滚正在运行的动画。但即便如此,您也必须跟踪当前的占用情况。 还是不行。特别是如果我每次需要不同的动画时都需要创建 anim 类的新实例。 根据 Robert C. Martin 的书 Clean Code,您应该将动画类拆分为 4 个类。一个用于淡入淡出,一个用于淡入淡出,等等......你不应该在一个类中制作 4 个动画。这本书amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/… 应该被每个开发者阅读。【参考方案3】:为了滑入和滑出我已经修改了你的类,以便使用小部件屏幕坐标:
public class WidgetAnimation extends Animation
private Element element;
private int currentOp;
private int startX=-1;
private int finalX=-1;
private final static int FADE_OUT = 0;
private final static int FADE_IN = 1;
private final static int SLIDE_IN = 2;
private final static int SLIDE_OUT = 3;
public WidgetAnimation(Element element)
this.element = element;
public void fadeOut(int durationMilli)
cancel();
currentOp = WidgetAnimation.FADE_OUT;
run(durationMilli);
public void fadeIn(int durationMilli)
cancel();
currentOp = WidgetAnimation.FADE_IN;
run(durationMilli);
public void slideIn(int durationMilli)
cancel();
currentOp = WidgetAnimation.SLIDE_IN;
run(durationMilli);
public void slideOut(int durationMilli)
cancel();
currentOp = WidgetAnimation.SLIDE_OUT;
run(durationMilli);
@Override
protected void onUpdate(double progress)
switch (currentOp)
case WidgetAnimation.FADE_IN:
doFadeIn(progress);
break;
case WidgetAnimation.FADE_OUT:
doFadeOut(progress);
break;
case WidgetAnimation.SLIDE_IN:
doSlideIn(progress);
break;
case WidgetAnimation.SLIDE_OUT:
doSlideOut(progress);
break;
private void doFadeOut(double progress)
element.getStyle().setOpacity(1.0d - progress);
private void doFadeIn(double progress)
element.getStyle().setOpacity(progress);
private void doSlideIn(double progress)
if(startX==-1)
finalX = element.getAbsoluteLeft();
startX = - Window.getClientWidth();
int positionX = (int) (startX + (progress * (this.finalX - startX)));
this.element.getStyle().setLeft(positionX, Unit.PX);
private void doSlideOut(double progress)
if(startX==-1)
startX = element.getAbsoluteLeft();
finalX = - Window.getClientWidth();
int positionX = (int) (startX + (progress * (this.finalX - startX)));
GWT.log("StartX:" + startX);
GWT.log("finalX:" + finalX);
GWT.log("positionX:" + positionX);
GWT.log("progress:" + progress);
this.element.getStyle().setLeft(positionX, Unit.PX);
我是水平滑出和滑入,但你可以修改代码。
希望对你有帮助。
【讨论】:
以上是关于GWT 中流畅的类 jQuery 动画的主要内容,如果未能解决你的问题,请参考以下文章