Setting Scroll positions in Flex
I recently struggled mightily with what I thought should be an easy problem. I had an image in flex and wanted to be able to pan around it and zoom in and out.
It turns out that a lot of people have a problem with this task, because how the scrollbars in flex keep track of where they are, and how flex handles the origin of a zoom operation. Read on for details.
In particular, if you start zoomed in on an image, or zoom in and move the image to recenter it, flex will crop the top and left sides that are invisible and won't allow you to scroll to them. This is because the scrollbars are pinned to (0,0) in the parent component, so you lose the image above the scrollbar, and to the left of the component. See here for an example:
http://www.sephiroth.it/weblog/archives/2007/11/flex_canvas_bug_when_it_is_zoomed_in.php
I thought I had a clever fix for this, but it took me a while to get it to work.
The way I tried to solve the problem was to do my zoom, and instead of moving the image to where I wanted it, I moved it to (0,0) and instead decided to set the scroll position manually.
I thought this was very clever, because after scaling, I could do something like:
this.horizontalScrollPosition = [some value];
this.verticalScrollPosition = [some value];
This seemed much better that trying to do a this.move(x,y) to re-center my scaled image.
Alas, everywhere I put the scroll position commands, it never seemed to work. Somewhere late in the process, they were being set back to 0.
I tried setting them in the object constructor, in the object creationCompleteHandler, in the application creationComplete handler, and everywhere else I could think of.
Finally I stumbled upon the callLater() command. It's magically delicious.
Then I was able to do this:
private function creationCompleteHandler(event:Event):void {
this.validateNow();
// callLater is needed because otherwise flex keeps resetting scroll position to 0
callLater(setZoomAndPosition);
}
private function setZoomAndPosition():void {
this.scaleX=[your scale value];
this.scaleY=[your scale value];
this.horizontalScrollPosition = [some value];
this.verticalScrollPosition = [some value];
}
And finally it respected my manual scroll posiitons.
As it turns out, this still was not a satisfactory solution to me, because I still had problems getting my other zoom functions to behave and I ended up going with a much more sophisticated solution. You can read about it here.
Even though I eventually abandoned this, I can imagine many instances where a programmer will need to set initial scroll positions, and it is helpful to know that the callLater function can be used in those cases.





Comments
Post new comment