Components inside a repeater not resizing as expected - apache-flex

I have an mxml panel in which I'm using a repeater. The panel can be resized horizontally and I would like for the repeated components to resize together with panel. Here is a simplified example of how things look like:
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" ...>
<!-- scripts and some controls -->
<mx:VBox width="100%">
<core:Repeater width="100%" dataProvider="model">
<ns1:MyItemRenderer width="100%" />
</core:Repeater>
</mx:VBox>
</mx:TitleWindow>
When I resize the component, the width of the repeated items does not change.
There also buttons and event handlers, which add and remove items from the model. When this is done, the repeater updates to display the correct number of items and all the items are resized correctly.
I have not been able to get the items to resize when the root panel is resized. I can see, that the VBOx around the repeater is getting a resize event. However, the repeated items are not getting the event. I tried to dispatch a resize event to the repeated items manually from a resize handler I hooked up to the VBox but that didn't help.
I also tried adding and removing a dummy-item from the ArrayCollection which is the dataProvider (because that triggers a correct resize otherwise as mentioned above) However, doing this in the resize handler of the VBox just leads to the repeater not showing any items at all.
Is there any way to get items in a repeater to resize with their enclosing container?
The ItemRenderer I'm using resizes correctly when used in a mx:List. It is built so it can work both with the data property set by the List container an getRepeaterItem() when used in a Repeater. In this particular case, I cannot use the List as a container because of the way it behaves with regards to controlling its height via the rowCount, height and maxHeight properties which doesn't work out for me in this particular case (I spare you the details).

override updateDisplayList in the titleWindow and when the height or width changes, invalidate the displayList on every item created inside the repeater.
That said, using repeaters are generally considered bad practice because every component inside it is rendered. A list based class--which makes use of renderer recyling is considered to be much more performant.
Based on your code segment, I can't tell whether your code could be re-worked without repeaters, or not.

For the record, I figured out the following "solution":
Use the maxHeight attribute on the box enclosing the repeater, binding it to an expression that derives the correct value from the other components... I still need to hardcode any space I want to reserve for components that come after the box containing the repeater if I don't want to have them pushed out of the enclosing panel but it is good enough for now.
essentially:
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" ...>
<!-- scripts and some controls -->
<mx:VBox id="outerBox" height="100%">
<mx:VBox id="innerBox" width="100%"
maxHeight="{outerBox.height - innerBox.y - 40}">
<!-- reserve 40 px for the button -->
<core:Repeater width="100%" dataProvider="model">
<ns1:MyItemRenderer width="100%" />
</core:Repeater>
</mx:VBox>
<mx:Button label="Stay Visible"/>
</mx:VBox>
</mx:TitleWindow>

Related

Auto scroll on focus of a dynamic flex form

First off here is the portion of .mxml that I am working with.
<s:Scroller id="scroller">
<s:VGroup id="vGrp" >
<mx:Form id="form"/>
</s:VGroup>
</s:Scroller>
I need the form to auto scroll based on the focused FormItem child that has focus. I have looked at this and tried this method. The issue that I am having is that my form is dynamically populated with FormItems. The example that I liked looks to only take into account that focusing will only happen to children of the VGroup. For me this is not the case and implementing the functions laid out in the linked website did not work for me (even after I did try to modify it to my particular case I was unable to get the scrolling to work properly). Any help would be much appreciated.

Extending DataGrid component, and adding buttons to it

I'd like to extend the standard DataGrid component in flex with mxml. But I want to add buttons to the bottom of the component. I've tried attempting the following but its not working...
Am I adding the Button to the wrong element?
<mx:DataGrid xmlns:fx = "http://ns.adobe.com/mxml/2009"
xmlns:mx = "library://ns.adobe.com/flex/mx"
xmlns:s = "library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
override protected function createChildren():void
{
super.createChildren();
listContent.addChild(button);
}
]]>
</fx:Script>
<s:Button id="button" label = "asdasdas"/>
</mx:DataGrid>
You need to define "Not working"! Are you getting compiler errors? Or runtime errors? Or is the button just not showing up? I'll assume the latter.
The DataGrid does not have any mechanism for positioning or laying out it's children. Your button most likely has a height and width of zero and resides at position 0,0; making it effectively invisible. Many Flex container classes have the ability to size and position their children; but the DataGrid is not a container and does not provide built in functionality for that. It focuses, primarily, on working with the columns array.
You will need to override the updateDisplayList() to position the function. Quite possibly you will need to make changes to commitProperties() and measure() along the way. You may also need to re-work how the columns are positioned and sized as to not interfere with your new button. If stuff is locked away in private methods (which is probable) then you're in a for a not-so-fun-time.
Read up on the Flex Component LifeCycle methods for more information and also review the DataGrid code to figure out what it does.
You may have an easier time just putting the button and DataGrid in a container, and treating that container as a single entity instead of trying to get a Button renderered inside of the DataGrid.
Got it. All I needed to do was replace listContent.addChild(button); with...
parent.addChild(button);
Thanks!

actionscript flex, how to send browser width to the swf itself

I'm working with flex, but actionscript ideas are just as good.
The flex <s:Application> tag has height="100%" width="100%" so the swf fits the browser as the browser gets resized.
My problem is that I have a <s:Label> that I need to position based on the real/current size of the browser.
<s:Application height="100%" width="100%">
.....
<s:Label text="hello" x="?" y=">" />
</s:Application>
I heard it's possible to use Application.application.width; but I get a compile error, that it doesn't know what that is.
Any ideas how to do this. I'm trying to get the current size of the swf in the browser, as the browser resizes.
As far as I can tell the following should work. Application.application simply is the same as this provided you are in the base application. The binding should allow the size to change after initialization.
<s:Application height="100%" width="100%">
.....
<s:Label text="hello" x="{width}" y="" />
</s:Application>
Edit : I just checked and it does work. To put your Label in the middle of the stage you simply have to put it like that
<s:Application height="100%" width="100%">
.....
<s:Label text="hello" x="{width/2}" y="{height/2}" />
</s:Application>
you could only know stage size when element is added inside stage, you could try a eventdelegate like this
app.addEventListener(Event.ADDED_TO_STAGE,init);
private function init(evt:Event):void{
trace(stage.stageWidth);
trace(stage.stageHeight);
}
Call a javascript function on browser resize. From there get the reference to the swf, and call the AS function to resize the label. Pass the browser width/height.
See example here
UPDATE: Correction: ExternalInterface goes AS to JS.
It's not completely clear what you are trying to do. x and y are positional elements, width and height are size elements. If you are positioning the label you should probably use top, left, right and bottom rather than x and y if you want it to size as the parent control sizes.
If you want the label centered you can use horizontalCenter and verticalCenter.
If you put it inside a layout control like a panel or a canvas you can just set its left and right to 0 and have the parent canvas size.
If your label is always in a different place depending on the size, you can override updateDisplayList to set the position. That holds whether you put it inside a layout control or not.

Limit width of custom list itemrenderer in Flex

I'm using a custom itemrenderer to display a list of photos and need to know how to control the width. At the moment it does this:
(source: tdwright.co.uk)
Which, as I'm sure you'll agree, is eye-bleedingly ugly.
The list is created like this:
<mx:Panel width="100%" height="100%" layout="absolute" title="Photos">
<mx:List x="0" y="0" width="100%" height="100%" id="photoList" dataProvider="{photos}" itemRenderer="thumbnails" rowHeight="100"/>
</mx:Panel>
And the itemrenderer component looks like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Image source="{data.src}" id="image" scaleContent="true" toolTip="{data.caption}" height="100%" horizontalAlign="center"/>
</mx:VBox>
I've tried placing width="100%" in a whole bunch of places, but without success. If anyone knows how I can control this I'd be very grateful.
If you set these properties inside the itemrenderer verticalScrollPolicy="off" horizontalScrollPolicy="off" the bars are disappeared
I don't know why they choose for the terrible "off" instead of False
A couple of observations here, based on a miasma of similar painful experiences. (Caveat: I have not built a test app to confirm everything here for this specific case)
Assuming that what you want is for the list to size its width based on the size of the itemRenderer elements it contains, those itemRenderer elements need to provide width information. Using a VBox in this fashion with scroll bars permitted means the VBox will attempt to "arbitrate" between the size of the content (Image) and the size of the parent. So yes, first thing to do is turn off the scrollbars on the VBox, assuming you can't just get rid of the VBox altogether. (I'm guessing you want the VBox so that you can put a title or something under the image as a next step)
The List as you have it specified is sized to 100% of its parent, the Panel, which is itself sized to 100% of its parent. Rather than size these elements "top down", consider letting their width be unspecified so that Flex will compute their required width bottom-up. Use maxWidth on the List or the Panel constrain their size if you need to for laying them out relative to their peers.
Another important thing to know about is the "minHeight=0" trick. Turns out, the sizing algorithm used by Flex behaves quite differently when minHeight or minWidth is set to something other than the default NaN. Setting it to 0 is extremely useful in many of these cases. Try minWidth=0 on the VBox and/or the List.
In addition to turning off the scrolling policy, set left and right to 0. That should anchor the width to the width of the parent.

Flex TabNavigator: When screen is left and returned, selectedChild is set, but tab bar highlights wrong tab

I have a TabNavigator that has a handful of children. The flow of the application allows the possibility of a user leaving the screen with this TabNavigator, then returning. When this happens, a method called on show of the parent canvas sets selectedChild to the first tab. When actually tested, the TabNavigator returns showing the text on the first tab, but the tab that is highlighted is whatever tab the user was on just before leaving.
Here is some pseudo-code that looks something like what I have:
<mx:Canvas show="init()">
<mx:Script>
<![CDATA[
private function init():void {
menutabs.selectedChild = tab1;
}
]]>
</mx:Script>
<mx:TabNavigator id="menutabs">
<mx:VBox id="tab1" label="Tab 1"><mx:Label text="First Tab Text" /></mx:VBox>
<mx:VBox id="tab2" label="Tab 2"><mx:Label text="Second Tab Text" /></mx:VBox>
<mx:VBox id="tab3" label="Tab 3"><mx:Label text="Third Tab Text" /></mx:VBox>
</mx:TabNavigator>
</mx:Canvas>
So what I am experiencing, for example, is going to another canvas with the application, having been on Tab 2, then returning to this canvas to see the text "First Tab Text" but the highlighted tab along the top is "Tab 2." I have tried handfuls of variations within the init() method of invalidateDisplayList, validateNow, and so on, with no change in the outcome.
Any ideas welcome.
This is the same issue seen in this question
I have also been suffering from the same problem and it appears to be a bug in the Flex framework's TabNavigator control. I have yet to find the solution though.
I have managed to find a temporary workaround:
TabNavigator's parent, referred to as The Parent, should dispatch an additional hide event on the TabNavigator when The Parent's visibility is set to false and dispatches the hide event on The Parent. This will trigger the redrawing of the control which eliminates overlapping content areas.
The Parent should reset TabNavigator selectedIndex to 0 in the hide handler for The Parent.
If you are having issues with TabNavigator tab styling when visibility changes, you can use
tabNavigator.notifyStyleChangeInChildren('tabStyleName',false) in the show handler for the tabNavigator to redraw the tab styles correctly.
I hope these are sufficient to cover your cases.
Did you observe that 'selectedChild' is an actual property of ViewStack, and not TabNavigator?
Since TabNavigator can be considered as ViewStack + TabBar, setting selectedChild has no effect on TabBar.
I suggest to use 'selectedIndex' than to set selectedChild. You can obtain the selectedIndex from the Container itself, using getChildIndex()
I left out a bit of information. My init() method does more than just selectedChild, and I think this other stuff, that didn't necessarily need to run every time, was what was screwing up the re-drawing of the tabs. So I created a new goHomeTab() method to call on show, and call my init() method only on initialize. All seems to be fine now. Thanks.

Resources