Friday, November 6, 2009

Video: Animated Scrollbar and Slider in Flex 4

Animated Scrollbar and Slider in Flex 4, the next episode in the gripping and suspenseful series CodeDependent, is now available from Adobe TV.

This show deviates a tad from the usual CodeDependent shtick; I don't actually walk through any code (shock! horror!). Instead, we show a couple of the new Flex 4 components in action and see the animated behavior that they have to help create a smoother, better user experience.

Here's the video:

Here is the demo application:

And here is the source code.

Finally, here's where you can find the CodeDependent videos on iTunes.

Enjoy.

7 comments:

Anonymous said...

Hello Chet,

Thank you for your continuous enlightening work.
Making transitions visible is particularly helpful in teaching applications, where a user should see/comprehend coherence/relation of the contents, instead of jumping.
Here is my question related to this post.
There is a content that is placed in a 'Scroller' component. I want to give a user an opportunity to easily navigate to particular part of the contents by clicking corresponding LinkButton that calls the function, which assigns necessary value to verticalScrollPostion property of the viewport of the scroller. Yeah, mouthful. Sorry.
To make scrolling smooth I use Animate class:
"s:Animate target='{scrollerID.viewport}' " and then "s:SimpleMotionPath property='verticalScrollPosition' valueTo='{somebindableVariable}' "
This works fine - the transitions are indeed very nice and smooth.
I thought that since the 'List' component does have 'scroller' property, I could use the same technique
in a List:
"s:Animation target='{listID.scroller.veiwport}' " and then "s:SimpleMotionPath property='verticalScrollPosition' valueTo='{someBindableVar}' "
Alas, it doesn't work. I get a warning: "Data binding will not be able to detect assignments to 'scroller'.
Could you advise me on the solution to that.
Just to make my problem clear: instant jumps DO work in "List". I simply assign the necessary value like this: "listID.scroller.viewport.verticalScrollPosition = value;"
But it would be nice to have visible scrolling, similar to what you demonstrate in this post.
Thank you,
Igor Borodin
P.S. Sorry, I don't know how to format the code in your blog.

Chet Haase said...

@Igor:
Good question. This is exactly the kind of thing I wanted when I posted my "Just for Show" query to get ideas for more tutorials. If something's not obvious (and many things aren't), it makes a great topic for a possible future show.

In the meantime, I played around with your problem and I see what you mean. The scroller object in the List (or, in the example I was playing with, the TextArea) is not bindable, so you also can't bind to any values inside of it. This makes it difficult to auto-populate targets and values on the animations. Fortunately, it's pretty easy to manually create the animations in script code on the fly, just grabbing the values dynamically instead of binding to them.

I got it working by writing a small script function like this:
private function scrollTo(endPosition:Number):void
{
var anim:Animate = new Animate(textArea.scroller.viewport);
anim.motionPaths = new <MotionPath>[
new MotionPath("verticalScrollPosition")];
anim.motionPaths[0].keyframes = new <Keyframe>[
new Keyframe(0), new Keyframe(500, endPosition)];
anim.play();
}
Then I called that function with the appropriate value that I wanted to scroll to.

I'll probably add this to the video tutorials I'm shooting this week, so look for it in more elaborate form whenever it's posted in the next few weeks, but hopefully the above function shows you what you need.

I'd like to find out if there's a way to do this through mxml with binding, but in the meantime, the script code isn't too bad...

Anonymous said...

Thank you very much indeed, Chet.

Your code works like a Swiss watch.
Frankly, this morning I tried to use Timer and (funny enough named the function scrollTo) it did work, but produced pretty choppy motion.
Your Animate class makes it amazingly smooth. Bravo!

Look forward to your future posts.
Igor Borodin

Anonymous said...

Hello, Chet.

Perhaps, you'll find this example of usage of the function you showed to me earlier quite illustrative as well.
In my application there are videos, where from time to time, using playheadPosition as a timer I give a user a visual cue that there are some side notes to read.
If a user choose to pause the video and read the side notes, I wanted the video get smoothly dimmed a bit while user is reading the notes.
And again I ran into the same issue: the video element of the video player does not allow binding.
And sure enough you function came to the rescue and allowed me to fade the video in and out smoothly.
So, your function may help people in various scenarios.
thanks,
Igor Borodin

Anonymous said...

Chet, your videos are helping me through the learning Flex process. Just wanted to point out a nuance in the animations / scrolling video post from 11-06. If you are reading just that blog post (not the whole thing), when you click on a Follower of yours, your sample application seems to overlay the Follower window.

That didn't seem to me to be expected behavior.

Chet Haase said...

@Anon: You're describing a bug that I'll glibly put down to weird blogger.com behavior (combined with cross-browser functionality - I can't see what you're talking about with IE on XP, just on Firefox).

There are a lot of quirks that I put up with for writing a techy blog on blogger, and this appears to be another one. On the other hand, if you can't view a demo and a follower profile at the same time, I'm not that concerned. I figure as long as you can see the video, play with the demo, read the blog text, and download the source code, then you got what I intended for you to get from the postings.

Mateusz said...

@Igor

You should just use AnimateProperty:

var animateProperty: AnimateProperty = new AnimateProperty(yourTarget);
animateProperty.property = "verticalScrollPosition";
animateProperty.toValue = newScrollValue;
animateProperty.play();

the solution with MotionPath is far too complicated for such easy problem;)