Flex 4 spark List width resize issue - apache-flex

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

Related

Scroll flex spark datagroup to maximum amount programmatically

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/

Flex resize image inside updateDisplayList

I have a custom component which is an HBox & I'm trying to resize a child which happens to be an image. This is image is inside a VBox which is also a child of the HBox. I have a number of these images so In UpdateDisplayList I call:
myimageArray[0-5].setActualSize(50,50);
but the image is never resized it just stays a large default size. The images source is a url path and I'm wondering if that is what is causing the problem?
You should call setActualSize() for each array item manually:
for each (var uiComponent:UIComponent in myimageArray)
{
uiComponent.setActualSize(50,50);
}
Or, if you need to resize only first 6 elements:
for (var i:int = 0; i < Math.min(6, myimageArray.length); i++)
{
myimageArray[i].setActualSize(50,50);
}

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

Algorithm to determine if a component is fully visible in Flex?

Is there a built in way to determine if a component is fully visible in a Flex application (i.e. not offscreen one way or the other). If not how would I go about figurin it out?
I want to show or hide additional 'next' and 'previous' buttons if my primary 'next' and 'previous' buttons are off screen.
What event would be best to listen to to 'recalculate' ? stage.resize?
thanks!
here is a method for calculating if the component is within the bounds of the stage, it will not however tell you if the component is being hidden by another component, or if the component is being hidden because it is outside the bounds of another container.
public function isComponentWithinStage(c:UIComponent):Boolean {
var tl:Point = c.localToGlobal(new Point(0, 0));
var br:Point = c.localToGlobal(new Point(c.width, c.height));
//are we off the left or top of stage?
if ( tl.x < 0 || tl.y < 0 ) {
return false;
}
var stage:Stage = Application.application.stage;
//off the right or bottom of stage?
if ( br.x > stage.width || br.y > stage.height ) {
return false;
}
return true;
}
Could you give the specifics of the visible item and the container(s) it's in? Is it a matter of having to scroll some container to get to the buttons? Or is it a matter of someone has dragged a child window of a flexlib:MDICanvas partially off screen?
I think it's going to come down to if the x,y position of the component is beyond the width and height of its container, (and so on up through the parent containers until you reach your top level Application.)

Flex: Custom Item Renderer For Combobox controls truncates text

I've implemented a custom item renderer that I'm using with a combobox on a flex project I'm working on. It displays and icon and some text for each item. The only problem is that when the text is long the width of the menu is not being adjusted properly and the text is being truncated when displayed. I've tried tweaking all of the obvious properties to alleviate this problem but have not had any success. Does anyone know how to make the combobox menu width scale appropriately to whatever data it's rendering?
My custom item renderer implementation is:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
styleName="plain" horizontalScrollPolicy="off">
<mx:Image source="{data.icon}" />
<mx:Label text="{data.label}" fontSize="11" fontWeight="bold" truncateToFit="false"/>
</mx:HBox>
And my combobox uses it like so:
<mx:ComboBox id="quicklinksMenu" change="quicklinkHandler(quicklinksMenu.selectedItem.data);" click="event.stopImmediatePropagation();" itemRenderer="renderers.QuickLinkItemRenderer" width="100%"/>
EDIT:
I should clarify on thing: I can set the dropdownWidth property on the combobox to some arbitrarily large value - this will make everything fit, but it will be too wide. Since the data being displayed in this combobox is generic, I want it to automatically size itself to the largest element in the dataprovider (the flex documentation says it will do this, but I have the feeling my custom item renderer is somehow breaking that behavior)
Just a random thought (no clue if this will help):
Try setting the parent HBox and the Label's widths to 100%. That's generally fixed any problems I've run into that were similar.
Have you tried using the calculatePreferredSizeFromData() method?
protected override function calculatePreferredSizeFromData(count:int):Object
This answer is probably too late, but I had a very similar problem with the DataGrid's column widths.
After much noodling, I decided to pre-render my text in a private TextField, get the width of the rendered text from that, and explicitly set the width of the column on all of the appropriate resize type events. A little hack-y but works well enough if you haven't got a lot of changing data.
You would need to do two things:
for the text, use mx.controls.Text (that supports text wrapping) instead of mx.controls.Label
set comboBox's dropdownFactory.variableRowHeight=true -- this dropdownFactory is normally a subclass of List, and the itemRenderer you are setting on ComboBox is what will be used to render each item in the list
And, do not explicitly set comboBox.dropdownWidth -- let the default value of comboBox.width be used as dropdown width.
If you look at the measure method of mx.controls.ComboBase, you'll see that the the comboBox calculates it's measuredMinWidth as a sum of the width of the text and the width of the comboBox button.
// Text fields have 4 pixels of white space added to each side
// by the player, so fudge this amount.
// If we don't have any data, measure a single space char for defaults
if (collection && collection.length > 0)
{
var prefSize:Object = calculatePreferredSizeFromData(collection.length);
var bm:EdgeMetrics = borderMetrics;
var textWidth:Number = prefSize.width + bm.left + bm.right + 8;
var textHeight:Number = prefSize.height + bm.top + bm.bottom
+ UITextField.TEXT_HEIGHT_PADDING;
measuredMinWidth = measuredWidth = textWidth + buttonWidth;
measuredMinHeight = measuredHeight = Math.max(textHeight, buttonHeight);
}
The calculatePreferredSizeFromData method mentioned by #defmeta (implemented in mx.controls.ComboBox) assumes that the data renderer is just a text field, and uses flash.text.lineMetrics to calculate the text width from label field in the data object. If you want to add an additional visual element to the item renderer and have the ComboBox take it's size into account when calculating it's own size, you will have to extend the mx.controls.ComboBox class and override the calculatePreferredSizeFromData method like so:
override protected function calculatePreferredSizeFromData(count:int):Object
{
var prefSize:Object = super.calculatePrefferedSizeFromData(count);
var maxW:Number = 0;
var maxH:Number = 0;
var bookmark:CursorBookmark = iterator ? iterator.bookmark : null;
var more:Boolean = iterator != null;
for ( var i:int = 0 ; i < count ; i++)
{
var data:Object;
if (more) data = iterator ? iterator.current : null;
else data = null;
if(data)
{
var imgH:Number;
var imgW:Number;
//calculate the image height and width using the data object here
maxH = Math.max(maxH, prefSize.height + imgH);
maxW = Math.max(maxW, prefSize.width + imgW);
}
if(iterator) iterator.moveNext();
}
if(iterator) iterator.seek(bookmark, 0);
return {width: maxW, height: maxH};
}
If possible store the image dimensions in the data object and use those values as imgH and imgW, that will make sizing much easier.
EDIT:
If you are adding elements to the render besides an image, like a label, you will also have to calculate their size as well when you iterate through the data elements and take those dimensions into account when calculating maxH and maxW.

Resources