I'm playing with GWT's Animation class as an exercise. My goal is not to create yet another widget/animation library for GWT. Also, I'm well aware that there are many libraries that do this. What I'm trying to do is learn how this can be done, not how to use some library. This is for educational purposes only....
With that said, I've implemented a simple class that performs 4 different animations on some widget: fade in, fade out, slide in, and slide out (following jQuery's animation model). See the code below for how I've implemented it.
LIVE DEMO: http://www.rodrigo-silveira.com/gwt-custom-animation/
My question: How can I smoothly [and successfully] stop an animation as soon as another one is triggered, and continue the current animation where the old one left off?
For example, if the slideIn() is half way through when slideOut() is called, how can I start sliding out from the widget's natural height of 50%? I tried keeping a member variable that always keeps track of the current progress so I could use that in a new animation, but can't seem to get it right. Any ideas?
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);
}
}
Usage
// 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);
You need to update the opacity based on the current value (equivalent to +=
or -=
assignments):
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);
}
Add a method cancelAnnimation and call this method everytime when the new annimation starts.
private bool canceled = false;
public void cancelAnnimation() {
canceled = true;
}
private void doFadeOut(double progress) {
if(!canceled) {
element.getStyle().setOpacity(1.0d - progress);
}
}
... etc.
So thats the way you can stop the animation. But now, you need to start the new animation from the current point. So the best was to modify the class again.
start the new animation with the offset from the first animation.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With