5

I would like my GWT widget to be notified when its CSS animation is over.

In plain HTML/Javascript this is easily done by registering an event handler like so:

elem.addEventListener("webkitAnimationEnd", function(){
    // do something
}, false);
// add more for Mozilla etc.

How can I do this in GWT?

This type of event is unknown to GWT's DOMImpl classes, so I keep getting an error:

"Trying to sink unknown event type webkitAnimationEnd".

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
barfuin
  • 16,865
  • 10
  • 85
  • 132

3 Answers3

5

Based on Darthenius' answer and Clay Lenhart's Blog, I finally settled for this solution:

private native void registerAnimationEndHandler(final Element pElement,
    final CbAnimationEndHandlerIF pHandler)
/*-{
    var callback = function(){
       pHandler.@fully.qualified.CbAnimationEndHandlerIF::onAnimationEnd()();
    }
    if (navigator.userAgent.indexOf('MSIE') < 0) {  // no MSIE support
       pElement.addEventListener("webkitAnimationEnd", callback, false); // Webkit
       pElement.addEventListener("animationend", callback, false); // Mozilla
    }
}-*/;

The CbAnimationEndHandlerIF is a simple custom EventHandler interface:

public interface CbAnimationEndHandlerIF extends EventHandler
{
    void onAnimationEnd();
}

Works like a charm! Thanks Darthenius!

If anyone can spot a weakness in this, of course I'd be happy to know.

barfuin
  • 16,865
  • 10
  • 85
  • 132
  • You are welcome. Nice abstraction for `callback`, by the way. – Rok Strniša Nov 25 '11 at 23:01
  • I just modified my code above to exclude MSIE, because MSIE cannot do CSS keyframe animations (at least up to version 9), and would also require a different syntax for adding the listener. – barfuin Dec 05 '11 at 23:20
1

You can always write some of the native (JavaScript) code yourself:

public class CssAnimation {
  public static native void registerCssCallback(
      Element elem, AsyncCallback<Void> callback) /*-{
    elem.addEventListener("webkitAnimationEnd", function() {
      $entry(@CssAnimation::cssCallback(Lcom/google/gwt/user/client/rpc/AsyncCallback;)(callback));
    }, false);
  }-*/;


  protected static void cssCallback(AsyncCallback<Void> callback) {
    callback.onSuccess(null);
  }
}

I haven't tried the code above. Let me know if it works as expected.


You can use GWT's Animation class to achieve the same effect. For example,

  new com.google.gwt.animation.client.Animation() {
    final com.google.gwt.dom.client.Style es = widget.getElement().getStyle();

    @Override
    protected void onUpdate(double progress) {
      setOpacity(1 - interpolate(progress));
    }

    private void setOpacity(double opacity) {
      es.setProperty("opacity", Double.toString(opacity));
      es.setProperty("filter", "alpha(opacity=" + 100 * opacity + ")");
    }

    @Override
    protected void onComplete() {
      /* ... run some code when animation completes ... */
    }
  }.run(2000, 5000);
Kev
  • 118,037
  • 53
  • 300
  • 385
Rok Strniša
  • 6,781
  • 6
  • 41
  • 53
  • Interesting, I didn't know that. But doing it this way will result in a scripted animation, not a CSS animation, right? GWT still does not know the event. Scripted animations have some drawbacks when it comes to smoothness of performance under heavy load or on some mobile devices. – barfuin Nov 24 '11 at 09:47
  • Yes, this will result in scripted animation, which might not be as CPU efficient as pure CSS animation. – Rok Strniša Nov 24 '11 at 09:52
  • 1
    @Kev It would have been better to keep these two answers separate ... The comments above refer to the section below the line (the scripted solution). The accepted answer is only the top part above the line, which describes a totally different approach. – barfuin Apr 30 '12 at 21:03
0

I expanded a bit on the solution from Darthenius. This code also includes a mechanism to remove the event handler when it is finished. This is what I needed for my application but may not be what you want in all contexts. YMMV!

My final code looks like this:

import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class CssAnimation {
    public static native void registerCssCallback(Element elem, AsyncCallback<Void> callback) /*-{
        var eventListener = function () {
            $entry(@CssAnimation::cssCallback(Lcom/google/gwt/user/client/rpc/AsyncCallback;)(callback));
            elem.removeEventListener("webkitAnimationEnd", eventListener);
        };

        elem.addEventListener("webkitAnimationEnd", eventListener, false);
    }-*/;

    protected static void cssCallback(AsyncCallback<Void> callback) {
        callback.onSuccess(null);
    }
}
Tim Mattison
  • 152
  • 10