A client of Blazing Cloud recently wanted to support animated screen transitions in their mobile platform and came to us for help. We decided to integrate the latest jQTouch (version 1, beta 2) into their framework since we had heard good things about it. Unfortunately, many animated transitions in Android don’t work very well. Worst is that slide transitions don’t work at all on Android 2.0 devices.
After poking around a bit, it seemed that the @-webkit-keyframes styles in jqtouch.css defined for the sliding transitions were being applied in parallel when running in Android 2.0. For example, a slide-in-from-right link has these webkit animated styles applied to it:
.in, .out { -webkit-animation-timing-function: ease-in-out; -webkit-animation-duration: 350ms; } .slide.in { -webkit-animation-name: slideinfromright; } @-webkit-keyframes slideinfromright { from { -webkit-transform: translateX(100%); } to { -webkit-transform: translateX(0); } }
On iPhone and Android 1.0 devices, a slide-in-from-right screen slides in correctly from 100% to 0 in about 350ms. But on Android 2.0 devices, the screen appears immediately as if no animation occurred.
To work around this problem, you have to manually set the start position first, then the end position and animation style. That is, instead of letting the @-webkit-keyframes do the work, you have to manually position the screen at 100%, then set the animation and final position style after a small time interval. For example, the key portion of the code to consider is:
toPage.css("webkitTransform", "translate3d(100%,0px,0px)"); setTimeout(function() { toPage.css({webkitTransitionDuration: "350ms", webkitTransitionTimingFunction: "ease-in-out"}); toPage.css("webkitTransform", "translate3d(0px,0px,0px)"); }, 5);
Note that we first set the starting position then wait about 5 milliseconds before applying the animated style (webkitTransitionDuration and webkitTransitionTimingFunction). After the transition completes, I clear the style from the page:
toPage.css({webkitTransitionDuration: null, webkitTransitionTimingFunction: null})
The sliding animation is handled in the animatePages function. Here’s the code with workaround (my changes in bold):
function animatePages(fromPage, toPage, animation, backwards) { // Error check for target page if(toPage.length === 0){ $.fn.unselect(); console.error('Target element is missing.'); return false; } // Collapse the keyboard $(':focus').blur(); // Make sure we are scrolled up to hide location bar scrollTo(0, 0); // Define callback to run after animation completes var callback = function(event){ if (animation) { if (animation.name == "slide") { var css = {webkitTransitionDuration: null, webkitTransitionTimingFunction: null}; toPage.css(css); fromPage.css(css); } toPage.removeClass('in reverse ' + animation.name); fromPage.removeClass('current out reverse ' + animation.name); } else { fromPage.removeClass('current'); } toPage.trigger('pageAnimationEnd', { direction: 'in' }); fromPage.trigger('pageAnimationEnd', { direction: 'out' }); clearInterval(dumbLoop); currentPage = toPage; location.hash = currentPage.attr('id'); dumbLoopStart(); var $originallink = toPage.data('referrer'); if ($originallink) { $originallink.unselect(); } lastAnimationTime = (new Date()).getTime(); tapReady = true; } fromPage.trigger('pageAnimationStart', { direction: 'out' }); toPage.trigger('pageAnimationStart', { direction: 'in' }); if ($.support.WebKitAnimationEvent && animation && jQTSettings.useAnimations) { tapReady = false; if (animation.name == "slide") { toPage.one('webkitTransitionEnd', callback); toPage.addClass('in current'); fromPage.addClass('out'); toPage.css("webkitTransform", "translate3d(" + (backwards ? "-100%" : "100%") + ",0px,0px)"); fromPage.css("webkitTransform", "translate3d(0px,0px,0px)"); setTimeout(function() { var css = {webkitTransitionDuration: "350ms", webkitTransitionTimingFunction: "ease-in-out"}; toPage.css(css); fromPage.css(css); toPage.css("webkitTransform", "translate3d(0px,0px,0px)"); fromPage.css("webkitTransform", "translate3d(" + (backwards ? "100%" : "-100%") + ",0px,0px)"); }, 5); } else { toPage.one('webkitAnimationEnd', callback); toPage.addClass(animation.name + ' in current ' + (backwards ? ' reverse' : '')); fromPage.addClass(animation.name + ' out' + (backwards ? ' reverse' : '')); } } else { toPage.addClass('current'); callback(); } return true; }
Note that jQTouch sets $.support.WebKitAnimationEvent to false for Android 2.0 devices even though it does support WebKit animation. Make sure you set that to true. Replace the animatePage function in your jQtouch with the function in this post and now you should be golden with iPhone and Android!
8 Comments
I hope Your brain compilator is working:
for(i=0; i<=10e10; i++) {
print("Thank You!");
}
after updating this function I get the problem with jumping form, issued here: http://code.google.com/p/jqtouch/issues/detail?id=398
It works only when I comment all lines with “translate3d” value, but then again the animations doesn’t work ;/
Tested on HTC Desire, Android 2.2
How do I set $.support.WebKitAnimationEvent to true for Android?
Figured it out. At the beginning section of jqtouch.js I made the following change to force true.
//$.support.WebKitAnimationEvent = (typeof WebKitTransitionEvent == “object”);
$.support.WebKitAnimationEvent = true;
Thank you x3 ! :) Just what I was looking for, and am still wondering why this isn’t fixed in the current version. Been going through the Jonathan Stark book.
Oooooh. I get it. I didn’t realize that one needs to slide “panels” (“cards”) into place inside a DIV via AJAX in an index.html file. Previously I had thought I would call some animate function on a hyperlink click that would go to another page. Instead, we need to intercept and prevent that click’s event bubble, and use the animation to slide the DIV into place. On load of index.html, it can use setTimeout() after load in order to asynchronously load the other “cards” (HTML files loaded with jQuery’s $(‘#mydiv’.load() call) into the DOM and keep them hidden until ready to animate into place.
Resovle jqtouch goBack() event.
@-webkit-keyframes slideinfromright{
from{-webkit-transform: translate3d(100%,0px,100px);}
to{-webkit-transform: translate3d(0,0px,0px);}
}
@-webkit-keyframes slideinfromleft{
from{-webkit-transform: translate3d(-100%,0px,-100px);}
to{-webkit-transform: translate3d(0,0px,0px);}
}
I could fix flash problem for Android2.2 and 2.3!
Very Very thank you from tokyo!!!
One Trackback
[...] This post was mentioned on Twitter by Tablet PC Info, junichi_y. junichi_y said: jQTouch slide transition fix for Android 2.0 –: http://bit.ly/hzOnp9 [...]