Scroll to selected item in Flex 4 Spark List component - actionscript-3

I'm setting selected element in s:List component with Actionscript, it works, but List doesn't scroll to selected item -- need to scroll with scrollbar or mouse. Is it possible to auto-scroll to selected item ? Thanks !

Try the s:List method ensureIndexIsVisible(index:int):void.

For Spark:
list.ensureIndexIsVisible(index);

This function will scroll to the top of the list in Flex 4+. It takes in account the height of the item, so it will work for lists with different items with different height.
private function scrollToIndex(list:List,index:int):void
{
if (!list.layout)
return;
var dataGroup:DataGroup = list.dataGroup;
var spDelta:Point = dataGroup.layout.getScrollPositionDeltaToElement(index);
if (spDelta)
{
dataGroup.horizontalScrollPosition += spDelta.x;
//move it to the top if the list has enough items
if(spDelta.y > 0)
{
var maxVSP:Number = dataGroup.contentHeight - dataGroup.height;
var itemBounds:Rectangle = list.layout.getElementBounds(index);
var newHeight:Number = dataGroup.verticalScrollPosition + spDelta.y
+ dataGroup.height - itemBounds.height;
dataGroup.verticalScrollPosition = Math.min(maxVSP, newHeight);
}
else
{
dataGroup.verticalScrollPosition += spDelta.y;
}
}
}

//try this
this.callLater(updateIndex);//where you want to set the selectedIndex
private function updateIndex():void
{
list.selectedIndex = newIndex;
list.ensureIndexIsVisible(newIndex);
}

In flex-3 there is a scrollToIndex method and hence you can call
list.scrollToIndex(list.selectedIndex);
I believe this should work in flex-4 too.

This worked for me. had to use the callLater.
list.selectedItem = "MyTestItem"; //or list.selectedIndex = 10;
this.callLater(updateIndex); //dispatch an update to list
private function updateIndex():void {
list.ensureIndexIsVisible(list.selectedIndex);
}

I saw this basic idea here...
http://arthurnn.com/blog/2011/01/12/coverflow-layout-for-flex-4/
public function scrollGroup( n : int ) : void
{
var scrollPoint : Point = theList.layout.getScrollPositionDeltaToElement( n );
var duration : Number = ( Math.max( scrollPoint.x, theList.layout.target.horizontalScrollPosition ) - Math.min( scrollPoint.x, theList.layout.target.horizontalScrollPosition )) * .01;
Tweener.addTween(theList.layout,{ horizontalScrollPosition: scrollPoint.x , time:duration});
}
protected function theList_caretChangeHandler(event:IndexChangeEvent):void
{
scrollGroup( event.newIndex );
event.target.invalidateDisplayList();
}

You'll probably want to access the List's scroller directly and do something like:
list.scroller.scrollRect.y = list.itemRenderer.height * index;

You can multiply the height of an element by its index and pass this value to:
yourListID.scroller.viewport.verticalScrollPosition

It is a bug - you can see the demonstration and a workaround at the https://issues.apache.org/jira/browse/FLEX-33660

This custom List component extension worked for me:
<s:List
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
valueCommit="callLater(ensureIndexIsVisible, [selectedIndex])">
</s:List>

I recently accomplished this in one of my projects by having a defined size for my items in the group..
<s:Scroller x="940" y="0" maxHeight="465" maxWidth="940" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<s:HGroup id="tutPane" columnWidth="940" variableColumnWidth="false" gap="0" x="0" y="0">
</s:HGroup>
</s:Scroller>
Following this my button controls for manipulation worked by incrementing a private "targetindex" variable, then I called a checkAnimation function, which used the Animate class, in combo with a SimpleMotionPath and a comparison between tutpane.firstIndexInView and target index. This modified the "horizontalScrollPosition" of the group.
This allowed separate controls to essentially act as a scroll bar, but I had the requirement of sliding the control to view the selected item.. I believe this technique could work for automated selection of items as well

Related

List with different column count

As the pic show(This is drawn by PhotoShop, not implemented yet), I want to implemnt a List like this one. It has different column count, say the first row has only one item, and the others have two items . I tried to use itemRendererFunction to detect the different item(the first row treat as a rendererA, the others treat as another rendererB),but it didn't work.
The cleanest solution to this problem, is to create a custom layout (we've discussed in the comments how Romi's solution will eventually cause too many problems). However, this is usually not an easy thing to do.
I will give you a rough sketch of what this custom layout might look like, so you can use it as a starting point to create one that does exactly what you need.
To create a custom layout, you must subclass BaseLayout and override and implement its updateDisplayList and measure methods.
To make things easier (and in order not to dump 500 lines of code in here), I used some hardcoded variables for this example. It assumes there will always be two columns, the first item will always be 200x200 px, and the other items will always be 100x100 px. There is no horizontalGap or verticalGap.
The consequence is of course that you can use this custom layout (as it is now) only for this specific List and these specific ItemRenderers. If you want it to be more generic, you'll have to do a lot more calculations.
But now for the code:
public class MyCustomLayout extends LayoutBase {
//hardcoded variables
private var columnCount:int = 2;
private var bigTileWidth:Number = 200;
private var bigTileHeight:Number = 200;
private var smallTileWidth:Number = 100;
private var smallTileHeight:Number = 100;
override public function updateDisplayList(width:Number, height:Number):void {
var layoutTarget:GroupBase = target;
if (!layoutTarget) return;
var numElements:int = layoutTarget.numElements;
if (!numElements) return;
//position and size the first element
var el:ILayoutElement = useVirtualLayout ?
layoutTarget.getVirtualElementAt(0) : layoutTarget.getElementAt(0);
el.setLayoutBoundsSize(bigTileWidth, bigTileHeight);
el.setLayoutBoundsPosition(0, 0);
//position & size the other elements in 2 columns below the 1st element
for (var i:int=1; i<numElements; i++) {
var x:Number = smallTileWidth * ((i-1) % 2);
var y:Number = smallTileHeight * Math.floor((i-1) / 2) + bigTileHeight;
el = useVirtualLayout ?
layoutTarget.getVirtualElementAt(i) :
layoutTarget.getElementAt(i);
el.setLayoutBoundsSize(smallTileWidth, smallTileHeight);
el.setLayoutBoundsPosition(x, y);
}
//set the content size (necessary for scrolling)
layoutTarget.setContentSize(
layoutTarget.measuredWidth, layoutTarget.measuredHeight
);
}
override public function measure():void {
var layoutTarget:GroupBase = target;
if (!layoutTarget) return;
var rowCount:int = Math.ceil((layoutTarget.numElements - 1) / 2);
//measure the total width and height
layoutTarget.measuredWidth = layoutTarget.measuredMinWidth =
Math.max(smallTileWidth * columnCount, bigTileWidth);
layoutTarget.measuredHeight = layoutTarget.measuredMinHeight =
bigTileHeight + smallTileHeight * rowCount;
}
}
And you can use it like this:
<s:List dataProvider="{dp}" height="300">
<s:layout>
<l:MyCustomLayout />
</s:layout>
</s:List>
Whenever you want to change the defined behavior of an existing component, always check first if you can solve the problem with skinning. It is a really powerful feature i Flex, and can also provide a solution in this case.
So, let's begin, assuming you already have your List, you only need to create a custom skin which "splits" the data provider in two parts, the first item, and all the others. So, let's assume we have this initial setup:
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var c:ArrayCollection = new ArrayCollection([
"String 1",
"String 2",
"String 3",
"String 4",
"String 5",
"String 6",
"String 7",
"String 8",
"String 9",
"String 10",
"String 11",
"String 12",
"String 13",
"String 14",
"String 15"]);
]]>
</fx:Script>
<s:List skinClass="CustomSkinList" dataProvider="{c}" />
As you can see, we define a custom list skin, which is just a copy of spark.skins.spark.ListSkin, the default skin for spark.components.List element.
Before we handle the data provider logic, we need to take a look at how the list items are rendered. This is done by using a DataGroup element, added to the skin, like so:
<s:Scroller left="0" top="0" right="0" bottom="0" id="scroller" minViewportInset="1" hasFocusableChildren="false">
<!--- #copy spark.components.SkinnableDataContainer#dataGroup -->
<s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
<s:layout>
<!--- The default layout is vertical and measures at least for 5 rows.
When switching to a different layout, HorizontalLayout for example,
make sure to adjust the minWidth, minHeight sizes of the skin -->
<s:VerticalLayout gap="0" horizontalAlign="contentJustify" requestedMinRowCount="5" />
</s:layout>
</s:DataGroup>
</s:Scroller>
Here is the place where we will have to make the changes, in order to get the first element to render differently. What we need to do, is just add another DataGroup, for rendering the first element in a custom way (this of course means using a custom item renderer). Now, our scroller looks like this:
<s:Scroller left="0"
top="0"
right="0"
bottom="0"
id="scroller"
minViewportInset="1"
hasFocusableChildren="false">
<!--- #copy spark.components.SkinnableDataContainer#dataGroup -->
<s:VGroup width="100%" height="100%">
<s:DataGroup id="firstItemDataGroup"
width="100%"
itemRenderer="CustomItemRenderer"
height="20">
<s:layout>
<s:VerticalLayout />
</s:layout>
</s:DataGroup>
<s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
<s:layout>
<!--- The default layout is vertical and measures at least for 5 rows.
When switching to a different layout, HorizontalLayout for example,
make sure to adjust the minWidth, minHeight sizes of the skin -->
<s:TileLayout horizontalAlign="center" requestedColumnCount="2" />
</s:layout>
</s:DataGroup>
</s:VGroup>
</s:Scroller>
Notice the 'firstItemDataGroup' addition, also the fact that it uses a different item renderer, than the default dataGroup element. With this new container in place we can proceed to render the elements. The custom skin need to override the parent initializationComplete() method, like so:
override protected function initializationComplete():void
{
useChromeColor = true;
if (hostComponent.dataProvider && hostComponent.dataProvider.length > 0)
{
var allItems:Array = hostComponent.dataProvider.toArray().concat();
firstItemDataGroup.dataProvider = new ArrayCollection([hostComponent.dataProvider.getItemAt(0)]);
var remainingItems:Array = allItems.concat().reverse();
remainingItems.pop();
var reversed:Array = remainingItems.reverse();
dataGroupProvider = new ArrayCollection(reversed);
}
super.initializationComplete();
}
What was added was just the 'if' block, and a private variable, named dataGroupProvider. This is because we will set the new dataProvider, the one starting from the second element, to the dataGroup element, in the updateDisplayList() method. Here is what it looks like:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
if (getStyle("borderVisible") == true)
{
border.visible = true;
background.left = background.top = background.right = background.bottom = 1;
scroller.minViewportInset = 1;
}
else
{
border.visible = false;
background.left = background.top = background.right = background.bottom = 0;
scroller.minViewportInset = 0;
}
// Here we assign the new data provider to the dataGroup element
if (dataGroupProvider)
dataGroup.dataProvider = dataGroupProvider;
borderStroke.color = getStyle("borderColor");
borderStroke.alpha = getStyle("borderAlpha");
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
In conclusion, just by creating a custom skin for our List element, we can use two containers for rendering the first item in a different way, from the rest of the elements. You shouldn't underestimate the power of Flex Skinning :)
Hope this helps. Have a great day!

Flex: spark DataGrid displays value other than the current value in dataProvider

I have 2 flex datagrids on a screen. The user can select one or more rows from either datagrid and move them to the other datagrid. The lower table is empty when entering the application. For example:
Item Color Price
--------------------
item57 red $5.55
item62 blue $5.29
item808 green $2.21
Row Item Color Price
---------------------------
Note there is a column that numbers the rows on the bottom datagrid (only).
When I enter the application and move, for example, 3 rows from the top to bottom grid, the row numbers are fine (they show rows 1, 2, and 3). For example:
Item Color Price
--------------------
Row Item Color Price
---------------------------
1 item57 red $5.55
2 item62 blue $5.29
3 item808 green $2.21
If I then move, for example, row 1 in the bottom grid back to the top...
Item Color Price
--------------------
item57 red $5.55
Row Item Color Price
---------------------------
1 item62 blue $5.29
2 item808 green $2.21
and then back again to the bottom grid...
Item Color Price
--------------------
Row Item Color Price
---------------------------
1 item62 blue $5.29
2 item808 green $2.21
1 item57 red $5.55
the row number is supposed to display 3 because it inserts into the bottom grid at the end of the list, but when it does this, it displays the (old) row number value of 1.
When I debug and look at the dataprovider = _myData, I see the rowNumber value for the row in question (for item57 above) equals 3 (as it should). However, it is displayed in the lower datagrid as 1.
How can the dataprovider value be different than what is displayed in the DataGrid?
[I can also debug and look at gridLower column information, and it also shows the correct value of 3 for rowNumber for the data in question.]
The lower datagrid is similar to the following (although I'm using a custom itemRenderer, removed for simplicity here):
[Bindable]
private var _myData:ListCollectionView=new ListCollectionView(new ArrayList());
...
<s:DataGrid dataProvider="{_myData}">
<s:columns>
<fx:Array>
<s:GridColumn id="gridLower" headerText="myHeader" dataField="rowNumber"/>
...
The function that adds the upper table's row(s) to the lower table is:
private function addRow():void {
var selectedIndices:Object=gridUpper.grid.selectedIndices;
for (var i:int=selectedIndices.length-1;i>=0;i--) {
var item:Object=_upperTableData.removeItemAt(selectedIndices[i]);
item.rowNumber=_myData.length+1;
_myData.list.addItem(item);
}
// I tried adding "_myData.refresh();" here and it had no effect
// I tried adding "ListCollectionView(gridLower.dataProvider).refresh();" and it had no effect
// I tried adding "grid2.dataProvider.refresh();" here but it had no effect
}
UPDATE 1: If I re-sort any column in the lower table, the correct values appear. I seem to be observing what's reported in this link:
http://www.barneyb.com/barneyblog/2007/06/23/another-flex-weirdnessgotcha/
Haven't found a solution yet though. See attempts in my addRow() function above. Am I on the right track?
UPDATE 2: While re-sorting manually corrects the data in the lower grid, I haven't found a way to do this programmatically. I tried inserting:
_myData.sort=null;
var complete:Boolean=_myData.refresh();
just before the end of addRow() function above, but it didn't resolve my issue. When debugging, complete is true, but still the lower grid displays the stale data.
New answer :) I will delete the old one if this helps.
I haven't used Spark DataGrid yet, was expecting it to behave like a List.
Found this in this in some comments in the source for this method of DataGrid:
public function invalidateCell(rowIndex:int, columnIndex:int):void
You can invalidate an entire row/col by passing -1 for the other value. In the quote from the docs below, you can also use dataProvider.itemUpdated()
If the specified cell is visible, it is redisplayed. If
variableRowHeight=true, then doing so may cause the height of the
corresponding row to change. If columnIndex is -1, then the entire row
is invalidated. Similarly if rowIndex is -1, then the entire column is
invalidated.
This method should be called when there is a change to any aspect of
the data provider item at rowIndex that might have some impact on the
way the specified cell is displayed. Calling this method is similar to
calling the dataProvider.itemUpdated() method, which advises the Grid
that all rows displaying the specified item should be redisplayed.
Using this method can be relatively efficient, since it narrows the
scope of the change to a single cell.
Now I finally know where the itemUpdated() method on collections (ArrayCollection, ListCollectionView) can actually be used!
[edit]
Give your grid an id:
<s:DataGrid id="lowerDataGrid" dataProvider="{_myData}">
Then you should be able to do this in your addRow() method after updating the collection:
lowerDataGrid.invalidateCell(item.rowNmber -1, 1); // assuming rowNumbers are 0 based
In my case, in my main class that contains the grid as an element, whenever I want to force a refresh of all the cells:
gridsDataProvider.addItemAt(new Object(), 0);
gridsDataProvider.removeItemAt(0);
But my GridItemRenderer needs to cater for the change in the data. So I created an updateDisplay method:
private function updateDisplay() : void {
if (transWindow != null) {
if (data == transWindow.total) {
if (field != "vat" && field != "total") {
textInput.visible = false;
} else {
line.visible = true;
textInput.enabled = false;
textInput.setStyle("fontWeight", "bold");
textInput.setStyle("fontSize", 14);
}
} else {
line.visible = false;
textInput.visible = true;
textInput.enabled = true;
textInput.setStyle("fontWeight", "normal");
textInput.setStyle("fontSize", 12);
}
}
}
This method is called from both the creationComplete handler ...
protected function init(event:FlexEvent):void
{
getTransWindow(event.target.automationOwner);
updateDisplay();
}
... well as the data setter of the GridItemRenderer
override public function set data(v:Object):void {
super.data = v;
if (v == null) {
textInput.text = "";
return;
}
var value : * = v[field];
if (value == null || value == undefined) {
textInput.text = "";
return;
}
if (value is Number)
textInput.text = Number(value).toFixed(2);
else
textInput.text = ""+value;
updateDisplay();
}
The mxml body of my renderer is quite simple:
<s:Line id="line" width="100%" visible="false" yFrom="1" yTo="1">
<s:stroke>
<s:SolidColorStroke color="0" weight="0"/>
</s:stroke>
</s:Line>
<s:TextInput id="textInput" y="2" restrict="0123456789." width="100%" height="100%" minWidth="10" borderVisible="false" textAlign="right"/>
O, in case you wondered, the getTransWindow method is just a method to retrieve the main calling class that contains the grid:
private function getTransWindow(par : *) : void {
if (transWindow != null)
return;
transWindow = par;
while (!(transWindow is TransactionWindow)) {
transWindow = transWindow.parent;
}
}
Hope this saves someone some time
Regards
Christo

Flex multitouch path scale dynamic registration issue

Is there any (straightforward) way to solve the dynamic registration issue with multitouch scaling events in flex? I just can't wrap my head around this.
What I've got is (amongst some lines and labels) a path in a group that itself is wrapped in a scroller;
<s:Scroller id="scroller">
<s:Group id="scrollerContent">
<s:Path id="path">
<s:stroke>
<s:SolidColorStroke color="#ffffff" weight="2"/>
</s:stroke>
</s:Path>
</s:Group>
</s:Scroller>
What I'd like to do is to zoom in and out on the path (and the other stuff in the scrollerContent group), so in my creationComplete() method I added an eventListener to the scrollerContent group:
scrollerContent.addEventListener(TransformGestureEvent.GESTURE_ZOOM, zoomEvent);
Here is the code Christophe Coenraets provided for his chart example (which does in fact scale the path, based on x=0 though;
private function zoomEvent(e:TransformGestureEvent):void
{
zoom(e.scaleX, e.scaleY);
}
protected function zoom(scaleX:Number):void
{
var w:Number = path.width * scaleX;
if (scaleX>1)
path.width = w > width*5 ? width*5 : w;
else
{
path.width = w < width ? width : w;
if (path.x + path.width < width) path.x = width - path.width;
}
}
I'm aware of the DynamicRegistration class, but can't get it working properly, it still scales the path based on the x=0 point.
DynamicRegistration.scale(scrollerContent, new Point(e.localX, e.localY), scrollerContent.scaleX*= e.scaleX, scrollerContent.scaleY=1);
Any help regarding this would be much appreciated!
I used the DynamicRegistration class, and got it working like this, if you're still interested:
protected function onZoom(e:TransformGestureEvent, img:Image):void
{
DynamicRegistration.scale(img, new Point(e.localX, e.localY), img.scaleX*e.scaleX, img.scaleY*e.scaleY);
}
Or with the native flex method:
protected function onZoom(e:TransformGestureEvent, img:Image):void
{
img.transformAround(new Vector3D(e.localX, e.localY, 0), new Vector3D(img.scaleX*e.scaleX, img.scaleY*e.scaleY, 0));
}

Getting TextArea on the stage (getChild by ID,Name)

I´m trying to get the 7 TextAreas on the stage on FlashBuilder,all of them have the id as "Desc1","Desc2","Desc3"... and the names are the same "Desc1","Desc2","Desc3"..., but when i try to get it,i get a error of a null object...
for(var i:int = 0;i<7;i++)
{
trace((stage.getChildByName("Desc"+(i+1))as TextArea).x);
}
I searched the web and dont find either any method of "getChildByID"
Flex IDs don't work with getChildByName(). getChildByName() is designed to work with ids of nested elements in Adobe Flash CS.
An flex id is an explicit declaration of a class member with name which is equal to the id.
Due to the lack of macro in the actionscript laguage you cannot automate the creation of such lists of controls.
You can manually create an Vector or an Array of the text areas and use it in other part of your code to automatically iterate over your TextAreas:
var text_areas:Vector.<TextArea> = new Vector.<TextArea>();
text_areas.push(Desc1, Desc2, Desc3);
// or you can do this
var text_areas2:Array = [];
text_areas["Desc1"] = Desc1;
text_areas["Desc2"] = Desc2;
text_areas["Desc3"] = Desc3;
// Now you can iterate over the text areas
for each (var a_text_area:TextArea in text_areas)
{
....
}
Or you can create a flex Array:
<fx:Array id="textAreas">
<s:TextArea id="textArea1"/>
<s:TextArea id="textArea2" x="397" y="0"/>
<s:TextArea id="textArea3" x="201" y="1"/>
</fx:Array>

Flex container with HTML style floating

I am using Flex 4 with Spark components to build a mobile application and I have a HGroup that I am using to contain all of my elements. When the screen loads it pulls in a small amount of text that will be displayed and loops through all the words to see if any of them are a keyword. While it is looping I am putting each word into its own label element and if the word is a keyword it changes a few styles and adds a click event to show a description about the word.
Everything runs fine but when everything is appended to the HGroup, there ends up being only one line and most of the text completely cut off because it will not wrap the content.
My Question is - Is there a way to set or extend the HGroup to allow content wrapping on its child elements?
Below are some code snippets of what I have:
MXML containers:
<s:VGroup id="answerData" width="580" height="700" horizontalAlign="center" paddingTop="5">
<s:HGroup id="theLabel" color="white" width="580" fontSize="25" paddingBottom="20" />
<s:HGroup id="theText" color="white" width="580" fontSize="25" maxWidth="580" />
</s:VGroup>
AS to create labels:
public static function setKeyWords(someText:String, theGroup:Group, theDictionary:Array, theView:Object):void {
theGroup.removeAllElements();
var textArray:Array = someText.split(' ');
for(var i:int = 0, l:int = textArray.length; i < l; i++) {
if(checkForWord(theDictionary, textArray[i].toString())) {
var theLink:Label = new Label();
theLink.text = textArray[i].toString();
theLink.setStyle("color", "0xFFFF00");
theLink.setStyle("fontWeight", "bold");
theLink.maxWidth = 580;
var tmpDescrip:String = theDescription;
theLink.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
showToolTip(tmpDescrip, theView);
});
theGroup.addElement(theLink);
} else {
var someLabel:Label = new Label();
someLabel.maxWidth = 580;
someLabel.text = textArray[i].toString();
theGroup.addElement(someLabel);
}
}
}
The issue that I was having is, I had multiple lables in a VGroup and needed them to wrap instead of extending past the containers set width. I was trying to integrate keywords into a dynamic paragraph of text. I could not use mx:Text because I needed each word to be its own component that allowed custom styling plus a mouse click even if the word was a keyword. Also the label max lines solution would not work because I am dealing with multiple lables in a VGroup and the VGroup needed to wrap its children not the label tags. I also could not use a TileGroup because it does not look right breaking a paragraph into a table looking component where each word is in its own column/row.
The solution I used was to count each character in the label being generated and add it to a variable to determine when I need to create a new HGroup that holds the labels and sits in a VGroup. I had to do this because I cannot determine the labels width until it renders because it is generated dynamically. This could not be done because as its render point is too late for me to move everything because the user can see all of this happening which is definitely not the desired effect.
Below is the code I used to solve this issue incase anyone else runs into this issue:
public static function setKeyWords(someText:String, theGroup:Group, theDictionary:Array, theView:Object):void {
theGroup.removeAllElements();
var textArray:Array = someText.split(' ');
var theCount:int = 0;
var theHGroup:HGroup = new HGroup();
var breakNum:int = 40;
theHGroup.percentWidth = 100;
for(var i:int = 0, l:int = textArray.length; i < l; i++) {
theCount += textArray[i].toString().length;
if(theCount >= breakNum) {
theGroup.addElement(theHGroup);
theHGroup = new HGroup();
theHGroup.percentWidth = 100;
theCount = 0;
}
if(checkForWord(theDictionary, textArray[i].toString())) {
theCount += 1;
var theLink:Label = new Label();
theLink.text = textArray[i].toString();
theLink.setStyle("color", "0xFFFF00");
theLink.setStyle("fontWeight", "bold");
theLink.maxWidth = 580;
//theLink.includeInLayout = false;
var tmpDescrip:String = theDescription;
theLink.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
showToolTip(tmpDescrip, theView, 'keywords');
});
theHGroup.addElement(theLink);
} else {
theCount += 1;
var someLabel:Label = new Label();
someLabel.maxWidth = 580;
someLabel.text = textArray[i].toString();
//someLabel.includeInLayout = false;
theHGroup.addElement(someLabel);
}
}
if(theCount > 0)
theGroup.addElement(theHGroup);
}
This may not be the most effecient way to do this but it does work and takes little time to execute on the Iphone which is what I was aiming for.
Not fully sure I understand your question.
If you mean the Label's are truncated, you might want to set a percentWidth and wrap Labels with maxDisplayedLines:
someLabel.maxDisplayedLines = 10;
If you mean you want columns and rows to your Group layout, use TileGroup / TileLayout.
If the children of your group contain composite content that must float, some kind of includeInLayout=false might help.
If you want text to show in block of several lines, use mx:Text with width set.
To display something above HGroup, easiest way is to leave HGroup alone and just make transparent container (Canvas) above it. There you'll be free to display anything (just do the math to position it correctly.)