Monday, October 29, 2018

Animating PowerApps

PowerApps does give you a few handy pieces that you can start assembling to make the UI a bit more interesting.  While animated slide in/out trays and menus are not provided by default, you can create them from the tools provided at least in some form or fashion.  Some of this is actually fairly easy if you have the right components to start with.
It looks so easy!

Do keep in mind that as I have mentioned in other posts, you cannot catch the OnHover or OnFocus events specifically, so you might be restricted on certain aspects.

As an example, I will start with a simple animated .GIF with a transparent background that I've included below.
Sooo pixelated!
This is actually a poorly sized (thanks Blogger) version of what is actually a nice animated .gif from PresenterMedia.  They've got a good array of PowerPoint images, backgrounds and animations which are handy for an array of applications and presentations.

In and of itself, the image gives some motion and life to a boring screen.  But, as this is a character holding onto some balloons, I'd expect it to float away.  So let's take this simple guy from the image above and turn it into something more "real".

Quick Start

In basic terms we will:
  • Initialize the start X/Y positions of our image/control/group
  • create a timer
    • Set a short Duration (e.g. 100ms)
    • Set Replay = true
    • Change the OnTimerEnd from "false" to 
      • a series of commands to increase/decrease X/Y of our image/control/group
      • an if/then to stop the timer from continuing once we've reached our X/Y destination
  • Something to start the timer (e.g. OnSelect of a certain control)

Initialize your variables

If this is the kind of thing that will be on a single page, then you should do it in a local variable via UpdateContext.  

In my example I am using a single animated .GIF, but you could do the same with a single, multiple singles or a group of controls.  For simplicity, we'll just stick with a single .GIF's X & Y starting and ending coordinates.  These are in pixels and will depend on both the size of the item you are moving and where you want it to move to.

In this example, I'm having my balloon guy float up and to the left.

Depending on how/when you want your animation to start, you will need to tie these initial variables to that event.  For now, we'll just do it with a Button.  Drop a Button on your screen and edit the OnSelect event to be the following:

UpdateContext({xStart:200}); //upper left starting position
UpdateContext({yStart:150}); //upper left starting position

UpdateContext({xEnd:-200});  //upper left ending position
UpdateContext({yEnd:-160});  //upper left ending position
UpdateContext({repeatTimer:true}); //should we keep going?
UpdateContext({startTimer:false})  //should we start the timer?
UpdateContext({startTimer:true})  //should we start the timer?


Or alternatively:

UpdateContext(
    {
        xStart:200, 
        yStart:150,
        xEnd:-200,
        yEnd:-160,
        repeatTimer:true,
        startTimer:false
    }
);
UpdateContext({startTimer:true});

We're essentially saying where the animation will start at and where it will finish at.  As well, we have two Booleans (start & repeatTimer) that we can alter around our needs for if we want the animation to start when the screen is displayed vs. on an event and also for when we reach our x or yEnd values.

I resized my animation to be 200x160, so I've set my xEnd / yEnd at -200 / -160.  Your #'s will be different depending upon where you're animating to/from and how large your object is.

NOTE: it is entirely OK to have an X/Y value that is off-screen.  The object will disappear/reappear as it slides on/off screen.  

One more item worth noting is the last two lines.  Notice I set the startTimer to false and then true.  A Timer's Start event will not fire unless it is true AND it changed from false.  So to ensure you are always really starting your timer you should first set it to false and then true.

Set up your timer(s)

The only way we can really do animation beyond an animated .GIF is via a looping timer.  Add a timer to your app and set the following parameters for it:

  • Duration : 50 (this is in milliseconds)
  • Repeat :  repeatTimer
  • Start : startTimer
  • OnTimeEnd : 
    • UpdateContext({xStart: xStart-1});
    • UpdateContext({yStart: yStart-1});
    • If(
    •    xStart <= xEnd Or yStart <= yEnd,  //have we reached either of our end points
    •    UpdateContext({repeatTimer: false})
    • )
Again, this is moving our animation from a position on-screen to the up and to the left.  You would adjust the logic/values above to fit your scenario.

We don't really have to have BOTH an xEnd and yEnd here, but I'm very aware of exactly how lazy I am and it is a good checkpoint on future errors.

Put in your object

In my case, I'm using an animated .GIF so I'll drop in a Media image object by clicking on Insert | Media | Image and then View | Media | Browse and upload my image. 

I should really use a smaller animation
Now select the Image object you created.  Go to the right-hand section of the screen and select Advanced.  Change the following parameters:
  • Image : (the name of the image file you uploaded w/o the extension)
  • x : xStart
  • y : yStart
When you change the X & Y values you'll notice that your animation will wind up in the top-left corner.  That's because these variables haven't really been initialized yet.  Until we click the button, those values for xStart and yStart are defaulted to Zero.  

NOTE: Of course you will want to either put your animation somewhere off-screen, or under another object, or make it visible on your starting event, or initialize some of this when the screen is displayed, etc.  There really are a lot of different ways you can approach it.

Make it all work

At this point, we just have an image, a button and a timer sitting on-screen.  Mine looks like this:
Sorta animated
Now let's make something really happen.  Click the button.  Your object should move to it's starting point and begin it's journey to the upper-left corner and beyond.

You will notice that the Timer display isn't changing even though the timer is running.  It is just that it is set to such a small # (i.e. 50ms) that it finishes and is reset before the control updates. 

The last thing you'd do in your own scenario is change the Timer control's Visible property to false (unless you enjoy staring at a non-functioning countdown display).

Final Thoughts

You can use this same method of course for moving control drawers in/out of frame and making controls slide in/out as a part of an enhanced UX.  However, keep in mind that there is still no control for OnHover or OnFocus and this might limit how easily certain things happen (e.g. the user must click "something" to start/stop your animation).  At this time, you can't have your control tray slide out of the top/side when the user moves their mouse into that area.  You'd need to put an icon there to be clicked and make everything appear.

You will also notice that in one of the earlier images above and that in the final one, my animation passed behind some other controls.  This has everything to do w/ the order in which things are listed on the left-hand side of your page.  Top items are on top and bottom items are on bottom.  
My BalloonGuy will appear under any object vs. over them
If you do pass an animation over a control object be aware that you won't be able to click on something while that animation is covering it.  

Despite the shortcomings noted above, there are some handy things you can still do w/ animations within PowerApps.  Using Timers to change X and/or Y values at a small enough increment will get you a smooth transition and make you look like a pro.


No comments:

Post a Comment

Because some d-bag is throwing 'bot posts at my blog I've turned on full Moderation. If your comment doesn't show up immediately then that's why.