Part 32: Animating Image Search Results

Part 32: Animating Image Search Results

Update: 2013-06-26
Share

Description

Source Code: https://aka.ms/absbeginnerdevwp8
PDF Version: https://aka.ms/absbeginnerdevwp8pdf

In this lesson we'll refine our search results page by animating the images as they are loaded from Flickr. We want the images to ease in, fade in to view. We also want to provide feedback to the user of the app for long running operations like retrieving these photos over a slow internet connection by adding a progress indicator. And finally, I want to add some feedback in case the user searches their current location and topics and Flickr has no results to return ... we don't want to leave the user in the dark waiting for photos to appear that never come.

So, our game plan in this lesson:

  1. We'll modify our LongListMultiSelector's DataTemplate -- we'll prepare the Image control for the fade in effect we'll implement
  2. We'll create an animation and storyboard targeting the image control to enable the fade in effect
  3. We'll make provisions for the possibility that there are no photos on Flickr that match our search criteria by creating and hiding a Text block that we'll un-hide when there are no photos to show
  4. We'll add a progress indicator that will run while we're performing the web service call to Flickr and loading the images

 

1. Prepare the Image control for a fade-in animation

The first step we'll take is to set the initial Opacity attribute of the Image to 0, indicating that we want to hide the contents of the image. 0 is completely transparent and 1 is completely opaque. 0.5 would be partially transparent / opaque.

Then, for each image in our DataTemplate, as that particular image has downloaded from Flickr, the ImageOpened event will fire. We'll handle that event and write code to animate the change of the Opacity attribute.

So, we'll make the following changes to the Image control:

Generic Episode Image

 

  1. Add an Opacity attribute, set it to 0
  2. Add an ImageOpened event handler attribute and wire it up to a new method called "Image_ImageOpenend", which we'll implement in the next step.

Right-click anywhere on that line of code with the ImageOpened attribute or it's setting, select "Navigate to Event Handler" from the context menu.

 

2. Implement the Image_ImageOpened Event Handler

Here we'll write C# code to animate the fade in effect. Many examples of animation you'll see use XAML to define both the Storyboard and Animations associated with the storyboard, then use C# code to kick off the animation when a certain event is triggered. We could do it that way, but we've chosen to do it all with C# because we're dealing with a special situation (more about that in a moment).

Animations are made up of a Storyboard object and at least one Animation object.

Let's start with the Animation. First, there are several different types of animation data types. We're using a DoubleAnimation data type because we want to move a property from 0.0 to 1.0. There's also a ColorAnimation class for animating between two colors, and a PointAnimation for modifying an objects X Y coordinate or it's size.

An Animation is basically a timeline combined with a result. The results are determined by the specific Animation class you pick like we just talked about. It's important to know that all Animation classes inherit from a Timeline class which confers properties related to timing of the animation ... the Begin time, allowing you to delay the start of animation, perhaps waiting for other animations on the storyboard to begin or complete, a Duration property that effects how long the animation should take before delivering the desired result -- how long should it take for our fade in effect, in this case. There's also AutoReverse and RepeatBehavior properties which do what they suggest.

A Storyboard is a collection of one or more Animations. You group the Animations you want triggered by a specific event, like a button click, a loaded event and so on. The Storyboard allows you to pair an Animation with a target object. The animation is just a definition of what property should be affected, when it should be affected and how long. We have to APPLY that Animation to a target object. In our case, that target object will be an Image control.

In our case, our Storyboard is simple ... we just want one thing to happen. We could add multiple Animations targeting multiple properties of multiple objects, and could even create child Storyboards to better refine how our user's experience will play out. Once we're ready to allow the Storyboard to play, we call its Begin() method. It will in turn kick off all it's child Animations and child Storyboards.

For a more complete explanation of animations, I'd recommend you start here:

https://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206955(v=vs.105).aspx

Back to our situation ... we need to animate each image as it's opened. We'll create an Animation to move the Opacity property from 0 to 1 thereby making it transform from completely transparent into completely opaque. We'll add the Animation to a Storyboard and then call Begin() on the Storyboard.

Generic Episode Image

Sometimes the animation is subtle to the untrained eye. To make the effect more dramatic, you can stretch the time from 500 milliseconds to something like 2000 or 3000 milliseconds, or rather, 2 or 3 seconds just for testing purposes.

Lines 74 and 75 use a SetTarget and SetTargetProperty syntax to pair up the animation and its target. You see a lot of Set___ and Get___ styled methods in the Windows Phone API, and that's due to the Windows Phone property system we talked about at the very outset of this series.

The Windows Phone property system allows us to use attached properties. If lines 68 through 75 were in XAML, it might look something like this:

<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ImageControlName"
Storyboard.TargetProperty="Opacity"
To="1.0" Duration="0:0:0.5" />
</Storyboard>

(Now, this approach is actually flawed because we would be targeting a single Image control. And as far as I know, you can't use a binding expression inside of the Storyboard.TargetName to make it dynamically apply to every image control in our data template, so this is one reason why a C# approach works better.)

I wanted to show the XAML version (flawed though it is) to illustrate what we're doing in our C# code ... in lines 74 and 75 we're ATTACHING the Storyboard.SetTarget and Storyboard.SetTargetProperty attached properties TO the DoubleAnimation object doubleAni, and setting their values appropriately. It looks like we're setting attributes of the Storyboard, but we're ATTACHING attached properties TO the DoubleAnimation.

One more curiosity about line 75. We're setting the Storyboard.TargetProperty to a new PropertyPath(OpacityProperty) ... what does this mean?

The rules of the Windows Phone property system require the target property of an animation must be set to a Dependency Property. Remember: that's one of the special powers of a Dependency Property -- that it can be animated, unlike regular old CLR properties. Fine, then why do we have to wrap it with the new PropertyPath object. That's difficult for me to explain, and for the sake of brevity let me point you to another article that can explain it with a good example:

PropertyPath XAML Syntax
Specifically, this link points to the anchor "PropertyPath for Animation Targets"
https://msdn.microsoft.com/en-us/library/ms742451.aspx#databinding_sa

In a nutshell, the PropertyPath is used to specify the property that is the target of an animation. We have a simple case, and so for now, I think it's easier just to understand that the PropertyPath object provides a map to find the dependency property we want to animate.

Let's make sure our images fade in by debugging the app:

Generic Episode Image

Mine works, and did you notice the half-second fade in? Very nice.

We've satisfied the topic of this lesson, but I wanted to add a few more features to our app while we're here. We'll provide feedback to the user to let them know the status of their searches against the Flickr API.

 

3. Add a TextBlock for "No Photos Found", a Progress Bar and TextBlock for "Loading"

Now, lets edit the MainPage.xaml again, sandwiching the LongListMultiSelector with two new passages of XAML:

Generic Episode Image

  1. We create a TextBlock element. A TextBlock is a simple XAML element for displaying small amounts of flow content. By "flow content" I mean textual content that dynamically adjusts and reflows the text content based on run-time variables such as window size, device resolution and other user preferences. There's quite a bit to Flow Documents in XAML ... I would point you to this resource for more information: https://msdn.microsoft.com/en-us/library/aa970909.aspx 

    At any rate, the TextBlock is just a way to
Comments 
00:00
00:00
x

0.5x

0.8x

1.0x

1.25x

1.5x

2.0x

3.0x

Sleep Timer

Off

End of Episode

5 Minutes

10 Minutes

15 Minutes

30 Minutes

45 Minutes

60 Minutes

120 Minutes

Part 32: Animating Image Search Results

Part 32: Animating Image Search Results

Bob Tabor, Clint Rutkas