Today we are going to visit the wonderful world of webkit animations. I’m going to demonstrate how you can use relatively simple CSS animations to bring your application to life. So start up Smart Mobile Studio and let’s get cracking! We begin by creating a brand new visual project. This is because we want to make use of visual controls rather than drawing stuff directly to the screen ourselves. So start by creating clicking on the “New project” button and fill in a suitable name.
Setting up the animation
Next step is to define the actual animation. This requires some knowledge of CSS but to be honest, it’s very easy and you will find tons of examples and pre-defined effects online. To define our animation first double-click on the “app.css” file in the project treeview. The file opens and you can edit the CSS.
Note: if you are having problems understanding CSS or lack the inspiration to come up with something unique – a great place to find ready made snippets to use is over at CSS Tricks. This is an awsome website with examples for pretty much every effect under the sun. So it’s well worth the visit.
So now comes the fun part – namely: what sort of animation do we want to create? Well, when my app starts I want it to load a picture and then quickly fade this picture into view. I also want it to scale from very small to normal size. This effect sort of comes at you out of nowhere, so a fitting name is “in your face”. So let’s define the animation:
@-webkit-keyframes InYourFace { 0% { opacity: 0.1; -webkit-transform: scale(0.1); } 100% { opacity: 1.0; -webkit-transform: scale(1.0); } }
As you can see above the animation is defined in C style, using curly brackets. It has two sections, one called 0% and another called 100%. These two sections basically represent the state of the object from beginning to end. You can also add as many sections as you like, in which case the sections become “key frames” (hence the tagname). How fast the keyframes play out depends on the duration property you set (see sourcecode example below). So in the CSS above we animate both the opacity of the object from barely visible to normal visibility, and also the scale of the object from 0.1 to 1.0 (which is the same as 100%).
Setting up the animation code
Next, we are going to need a picture to play with, so i’ve added a picture to my project (Buddhas_beauty.jpg), just find a picture that you want to play around with and add it to the project. You do this by right-clicking on the resources node in the project treeview, clicking “add resource file” from the pop-up menu.
Next, double-click on the file “form1”, which brings up the object pascal code for your form. This form is automatically created by the IDE for you – so you dont need to write it all yourself. We will be adding an image and an animation player object. We will also override a couple of methods to trigger the animation at the right time. Here is the interface section of our form:
TForm1=class(TW3form) private { Private methods } FImage: TW3Image; FAnim: TW3NamedAnimation; Procedure HandleImageLoaded(Sender:TObject); protected { Protected methods } Procedure InitializeObject;override; Procedure FinalizeObject;override; Procedure StyleTagObject;override; Procedure ReSize;override; end;
In the constructor (InitializeObject) we setup the objects we want to use. This is more or less identical to ordinary Delphi, except for the names of-course which has been obscured to protect the binary otherwise located (that was a joke).
Procedure TForm1.InitializeObject; Begin inherited; (* setup the image *) FImage:=TW3Image.Create(self); FImage.Visible:=False; FImage.OnLoad:=HandleImageLoaded; FImage.LoadFromURL('/res/buddhas_beauty.jpg'); (* setup the effect for our image *) FAnim:=TW3NamedAnimation.Create; (* and tell the object the CSS name *) FAnim.AnimName:='InYourFace'; End; Procedure TForm1.FinalizeObject; Begin FImage.free; FAnim.free; inherited; End;
Since Javascript is “non blocking” we have to use events to know when a picture has loaded. So to make it short – that’s when we want to trigger our animation. If we tried it before the image was ready we would get an error (or, depending on the object state, nothing would happen).
Procedure TForm1.HandleImageLoaded(Sender:TObject); Begin (* image is loaded, now start the effect & make it visible *) FAnim.Duration:=0.2; FAnim.Execute(FImage); FImage.Visible:=True; end;
The rest of the code is fairly self describing, especially if you have been following our other examples. The rules are simple: position your controls in the resize method and set styles in the StyleTagObject method. Some rules can be broken and others bent – but these are the ground rules for the VJL.
Procedure TForm1.StyleTagObject; Begin inherited; StyleClass:='TW3CustomForm'; End; Procedure TForm1.ReSize; Begin inherited; (* position image *) FImage.setBounds(10,10,width-20,height-20); end;
Another way to trigger an animation on an object is to go low-level. You can for instance run an animation forever using a simple style call as such:
w3_setStyle(FHeader.TagRef,'-webkit-animation', 'TitleGrow 1s infinite alternate');
The above code will execute an animation called “titlegrow” forever. But ofcourse you lose the high level benefits of a pascal interface and also no event callbacks. But if you just want something to move up and down, or some other transformation – then the above one-liner will do the trick.
The final result
Sadly I cant show you a video of the output, but it works just as expected. The application executes, loads the picture – and when the picture is loaded it scales at you out of nowhere into full size (I later added a label to the top of the display). Click here to download the project
Here is the same app running in iPad mode. I added some simple resize code to make the font scale with the size of the display. Not bad for less than 5 minutes of coding! Put that in your pipe and smoke it Macromedia 😉
Looks interesting. I have to wonder, though, since a TW3NamedAnimation requires a name to work, why not put that into the constructor instead of passing it later?
When i wrote this class I was usure about a few things regarding the RTL. We had to build the road as we went along – so i wanted to make sure it would be “persistent friendly” as much as possible.
It is easier to persist object that have no parameters in the constructor, because all you need to know is the type-name.
I am going to clean up the RTL before we go “live” and will revise every class and object in the RTL. I will also add my TW3AnimationQueue – so you can triger series of animations in sequence.