Scroll flex spark datagroup to maximum amount programmatically - apache-flex

I have a spark skinnable component which contains a datagroup with images. The datagroup is scrolled by hovering the mouse over it. Everything works fine except one thing: after I change the datagroup provider, I need to scroll down automatically. The problem is the images are not loaded immediately after I set the provider so (contentHeight - height) does not yet represent the actual maximum scrolling position. Is there an easy way of telling the datagroup to scroll down as its content loads? Because the workaround seems to be not so straightforward.
This is the code for scrolling(thumbnailStrip is my datagroup):
private function thumbnailStrip_mouseMoveHandler(evt:MouseEvent):void {
var fr:Number = (thumbnailStrip.contentHeight - thumbnailStrip.height) / thumbnailStrip.height;
var scroll:Number = fr * evt.stageY - fr * this.y;
var ms:Number = maxScroll();
if(scroll > ms) scroll = ms;
thumbnailStrip.verticalScrollPosition = scroll;
}
private function maxScroll():Number {
return thumbnailStrip.contentHeight - thumbnailStrip.height;
}
Thanks,
Calin

thumbnailStrip.layout.verticalScrollPosition += thumbnailStrip.layout.getVerticalScrollPositionDelta(NavigationUnit.END);
This may have to run a few times to get all the way to the bottom.It's supposed to return the difference between the current scroll position and the "end" of the scroll position. As things load, I'd just keep calling this in a "callLater".
btw, there's a bug for this: http://bugs.adobe.com/jira/browse/SDK-25740 not sure if it's fixed in 4.5, ugly workaround here: http://flexponential.com/2011/02/13/scrolling-to-the-bottom-of-a-spark-list/

Related

Flex 4 spark List width resize issue

I've got a spark List with an item renderer. When I click on an element, the renderer becomes larger and when I click again, it becomes small again.
The problem is that list doesn't resize with the content. I've tried to dispatch an event from the renderer passing its content size and resize list in this way:
private function refreshList(event:ResultEvent):void
{
var size:Number = (event.result as Number) + 6;
if (size >= mylist.width)
{
consultingNumber++;
mylist.width = size;
}
else
{
consultingNumber--;
if (consultingNumber == 0)
mylist.width = size;
}
mylist.invalidateDisplayList();
}
consultingNumber is the number of 'opened' renderer.
It works quite well, but when all renderer is 'closed' an horizontal scrollbar appear.
Tracing list's width it result correct but the scrollbar is there even if I set horizontalScrollPolicy to off.
Try calling myList.invalidateSize() instead of myList.invalidateDisplayList();
Here is some more information about the flex component lifecycle which should get you on the right track:
http://weblog.mrinalwadhwa.com/2009/06/21/flex-4-component-lifecycle/
http://www.slideshare.net/rjowen/adobe-flex-component-lifecycle-presentation
Cheers

Canvas' verticalScrollPosition cannot be changed in Flex

I have a weird problem with verticalScrollPosition in Flex.
I have a content Canvas and a wrapper Canvas. The content is large (5000px X 5000px), the wrapper is 800px X 800px.
public var wrapper:Canvas = new Canvas();
public var content:Canvas = new Canvas();
wrapper.addChild(content);
application.addChild(wrapper);
I would like to set the wrapper's scrollbar position dynamically anytime. I can do it by calling its properties:
wrapper.verticalScrollPosition = A;
wrapper.horizontalScrollPosition = B;
This is working fine. But! If I set a default scrollbar position when the Canvas is complete:
wrapper.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void{
wrapper.verticalScrollPosition = DEFAULT_A;
wrapper.horizontalScrollPosition = DEFAULT_B;
});
I can't set the verticalScrollPosition anymore:
wrapper.verticalScrollPosition = C;
trace(wrapper.verticalScrollPosition); // Outputs: DEFAULT_A
So the problem only exist if I set a default position using 'FlexEvent.CREATION_COMPLETE'.
What am I doing wrong here?
Thanks in advance.
I've found a horrible workaround - I wait 1 microsecond to set the default state:
wrapper.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void{
setTimeout(
function():void{wrapper.verticalScrollPosition = DEFAULT_A;},
1
);
});
I think we can agree it's really ugly. How can I make it better?
I've found the problem. I attached the event listener to the child of the wrapper. When I added the listener to the wrapper itself it works.
So lesson I've learnt: always track the topmost ui element's events you have to work with.

How do I Print a dynamically created Flex component/chart that is not being displayed on the screen?

I have a several chart components that I have created in Flex. Basically I have set up a special UI that allows the user to select which of these charts they want to print. When they press the print button each of the selected charts is created dynamically then added to a container. Then I send this container off to FlexPrintJob.
i.e.
private function prePrint():void
{
var printSelection:Box = new Box();
printSelection.percentHeight = 100;
printSelection.percentWidth = 100;
printSelection.visible = true;
if (this.chkMyChart1.selected)
{
var rptMyChart1:Chart1Panel = new Chart1Panel();
rptMyChart1.percentHeight = 100;
rptMyChart1.percentWidth = 100;
rptMyChart1.visible = true;
printSelection.addChild(rptMyChart1);
}
print(printSelection);
}
private function print(container:Box):void
{
var job:FlexPrintJob;
job = new FlexPrintJob();
if (job.start()) {
job.addObject(container, FlexPrintJobScaleType.MATCH_WIDTH);
job.send();
}
}
This code works fine if the chart is actually displayed somewhere on the page but adding it dynamically as shown above does not. The print dialog will appear but nothing happens when I press OK.
So I really have two questions:
Is it possible to print flex components/charts when they are not visible on the screen?
If so, how do I do it / what am I doing wrong?
UPDATE:
Well, at least one thing wrong is my use of the percentages in the width and height. Using percentages doesn't really make sense when the Box is not contained in another object. Changing the height and width to fixed values actually allows the printing to progress and solves my initial problem.
printSelection.height = 100;
printSelection.width = 100;
But a new problem arises in that instead of seeing my chart, I see a black box instead. I have previously resolved this issue by setting the background colour of the chart to #FFFFFF but this doesn't seem to be working this time.
UPDATE 2:
I have seen some examples on the adobe site that add the container to the application but don't include it in the layout. This looks like the way to go.
i.e.
printSelection.includeInLayout = false;
addChild(printSelection);
Your component has to be on the stage in order to draw its contents, so you should try something like this:
printSelection.visible = false;
application.addChild(printSelection);
printSelection.width = ..;
printSelection.height = ...;
...
then do the printing
i'm not completely sure, but in one of my application I have to print out a complete Tab Navigator and the only method i have found to print it is to automatically scroll the tabnavigator tab in order to show the component on screen when i add them to the printjob.
In this way they are all printed. Before i created the tabnaviagotr scrolling the print (to PDF) result was a file with all the pages of the tab but only the one visible on screen really printed.

Flex/AS3: changing width/height doesn't affect contents

I thought I had a handle on AS3, DisplayObjectContainers, etc. but this basic thing is really confusing me: changing the width/height of a sprite does not affect it's visual contents - either graphics drawn within it or any children it may have.
I have searched around and found an Adobe page that represents my own little test code. From that page, I would expect the sprite to increase in visual size as it's width increases. For me, it doesn't. (http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/display/DisplayObject.html#width)
width property
width:Number [read-write]
Indicates the width of the display object, in pixels. The width is calculated based on the bounds of the content of the display object. When you set the width property, the scaleX property is adjusted accordingly, as shown in the following code:
My code below doesn't affect the visual display at all - but it does set the width/height, at least according to the trace output. It does not affect the scaleX/scaleY.
What the heck am I missing here??
My setup code:
testSprite = new SpriteVisualElement();
var childSprite:SpriteVisualElement = new SpriteVisualElement();
childSprite.graphics.beginFill(0xFFFF00, 1);
childSprite.graphics.drawRect(0, 0, 200, 100);
childSprite.graphics.endFill();
childSprite.name = "child";
testSprite.addChild(childSprite);
container.addElement(testSprite);
testSprite.addEventListener(MouseEvent.CLICK, grow);
}
public function grow(event:MouseEvent):void
{
event.target.width += 5;
event.target.height += 5;
trace("grow", event.target.width);
}
If I understand the code correctly; you are changing the width / height of the sprite. But you are doing nothing to change the width/ height of the sprite's children.
In the context of a Flex Application, you can use percentageWidth and percentageHeight on the child to resize the child when the parent is resized. You could also add a listener to the the resize event and adjust sizing that way; preferably tying in to the Flex Component LifeCycle methods somehow.
I believe these approaches are all Flex specific, and dependent upon the Flex Framework. Generic Sprites, as best I understand, do not automatically size themselves to percentages of their parent container; and changing the parent will not automatically resize the parent's children.
I bet something like this would work:
public function grow(event:MouseEvent):void
{
event.target.width += 5;
event.target.height += 5;
childSprite.width += 5;
childSprite.height += 5;
trace("grow", event.target.width);
}
First, if you have a problem with a flex component, you can look over its source code.
In my environment, (as I installed flex SDK to C:\flex\flex_sdk_4.1), the source code for SpriteVisualElement is located at
C:\flex\flex_sdk_4.1\frameworks\projects\spark\src\spark\core\SpriteVisualElement.as
In the source code, you'll find that width property is overridden :
/**
* #private
*/
override public function set width(value:Number):void
{
// Apply to the current actual size
_width = value;
setActualSize(_width, _height);
// Modify the explicit width
if (_explicitWidth == value)
return;
_explicitWidth = value;
invalidateParentSizeAndDisplayList();
}
So, you cannot expect the auto-scaling of the component.
Making custom components will be one solution.
Here is a sample implementation of custom component.
Custom Component Example - wonderfl build flash online

Flex: Get height of children...when to call function?

I have a function I wrote that gets the height of the application without scrolling. Meaning the height it would need to be to not have to scroll.
This is the function:
private function getContentHeight():Number
{
var height:Number = 0;
for(var i:uint = 0; i<this.numChildren; i++)
{
var d:DisplayObject = this.getChildAt(i) as DisplayObject;
//trace(d.name+":"+d.height);
height += d.height;
}
height += Number(this.getStyle('verticalGap'))*this.numChildren;
height += Number(this.getStyle('paddingTop'));
height += Number(this.getStyle('paddingBottom'));
return height;
}
This function works well but the problem is knowing when to call it. I planned on calling it after I add/remove any children from it. However thats still too soon because I don't get the correct height yet if I run it then. The fix I currently have is using a Timer to call the function about 300 milliseconds after a child is added/removed which seems to work well but I think this is a very risky fix. So I was wondering a better solution. I am thinking there has to be some sort of event I can listen for that will tell me when its ready for me to run this function, I just don't know what event that would be?
Thanks!
First of all, take a look at measuredWidth and measuredHeight properties of UIComponent (so all the controls and containers have these properties), flex already measures required width/height of the containers.
Secondly, the right place to look at this properties are creationComplete and updateComplete events. In your case, if you add some children programmaticaly, you should handle updateComplete event after you've added you children.

Resources