I have the following code to create a ViewStack which is used as a dataprovider for a TabBar:
<s:TabBar id="objectTab" dataProvider="{vs_objects}"/>
<mx:ViewStack id="vs_objects" width="100%" />
I want to constrain the number of children the ViewStack to avvoid the tabs going out of the screen when the user opens many tabs without closing any. I attempt to do this by removing the oldest element in the ViewStack when the user opens a new tab and the size of the ViewStack is above 9.
private function openTab(object:Object): void {
//Create a new NavigatorContent(form) and add it to the ViewStack
........
vs_objects.addChild(form);
if(vs_objects.numChildren > 9) {
vs_objects.removeChildAt(0);
}
//vs_objects.selectedChild = form;
vs_objects.selectedIndex = (vs_Tiltaksbanken.numChildren -1);
}
The image below illustrates my problem, where the dark grey color illustrates the selected Tab. There should only be one selected tab, which works perfectly fine with both the child selection approaches above, when i don't remove a child before selecting a new. When i remove a child and then open a new Tab, the new Tab does not get selected properly, it only gets "painted" in the selected color. In This case Tab 40 is still shown when i open Tab 41 (exceeding 9 tabs). The result of this issue is that Tab 41 is not rendered completely.
Does anyone know how i can fix this problem, or have a different approach for constraining the number of Tab's/ViewStack-children?
UPDATE:
The problem was my AS3 code inside the childrens NavigatorContent's that caused the application to behave this way. The solution was using the callLater method:
The solution to my problem was using the callLater method as shown below with Adnan Doric's code example:
protected function openTab():void
{
var form:Container = new Container();
form.name = "Tab " + counter++;
vs_objects.addChild(form);
vs_objects.selectedChild = form;
callLater(removeTab);
}
private function removeTab(): void {
if (vs_objects.numElements > 10)
vs_objects.removeElementAt(0);
}
Try this, even though I'm not sure it is the correct solution, maybe it's better to implement some kind of scrolling.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.core.Container;
private var counter:int = 1;
protected function openTab():void
{
var form:Container = new Container();
form.name = "Tab " + counter++;
vs_objects.addChild(form);
if (vs_objects.numElements > 10)
vs_objects.removeElementAt(0);
vs_objects.selectedChild = form;
}
]]>
</fx:Script>
<s:TabBar id="objectTab" top="32" labelField="name" dataProvider="{vs_objects}"/>
<mx:ViewStack id="vs_objects" width="100%" />
<s:Button label="addTab" click="openTab()" />
</s:Application>
Hope that helps :)
Related
i have 2 event
one is list change
one is button click
I want to click button but sometimes click list item
how to fix , thanks
image http://img.my.csdn.net/uploads/201112/21/0_1324478869TXbz.gif
<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
labelField="title"
messageField="message"
iconField="ico"
iconWidth="64"
iconHeight="64"
initialize="init()">
<fx:Script>
<![CDATA[
import spark.components.Button;
private var delButton:Button;
private function init():void{
if(!delButton){
delButton=new Button();
delButton.addEventListener(MouseEvent.CLICK,handleClick);
delButton.x=this.parent.width-70;
delButton.y=20;
delButton.height=30;
delButton.width=50;
delButton.label="aa";
this.addChild(delButton);
}
}
private function handleClick(event:MouseEvent):void{
}
]]>
</fx:Script>
</s:IconItemRenderer>
I didn't use flex components and I'm not sure exactly how you add childs to them but the general idea is that you draw transparent rects on the top of the components that are not overlaping and add event listeners to those rects instead of to components directly - that way you won't miss your button.
I want to add scrollbar to the flex tootip. So i created custom tool tip. Below is the code snippet. Problem i am facing is that as soon as i move the mouse on the custom component tooltip, the custom component tooltip disppear. i have alse set the ToolTipManager.hideDelay = Infinity. I want to use the scrollbar of the cutom tool tip.
I do not want the custom tool top to hide till i move the mouse outside the custom tool tip component.Currently it hide itself once i move the mouse outside the label. How to control the destroy of tool tip.
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%"
height="100%"
implements="mx.core.IToolTip">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
private var _bodyText:String = "";
[Bindable]
public function get bodyText():String
{
return _bodyText;
}
public function set bodyText(value:String):void
{
_bodyText = value;
text = value;
}
private var _text:String;
public function get text():String
{
return _text;
}
public function set text(value:String):void
{
_text = value;
}
]]>
</fx:Script>
<s:Scroller width="100%" height="200">
<s:RichEditableText text="{bodyText}" width="100%" height="100%" color="red"/>
</s:Scroller>
</s:Group>
and i add this cutom tooltip on mx:label component on toolTipCreate event.
protected function label1_toolTipCreateHandler(event:ToolTipEvent):void
{
ScrollableToolTip ptt = new ScrollableToolTip();
ptt.bodyText = data.notes;
ptt.height = 300;
ptt.width = 100;
event.toolTip = ptt;
}
Any pointers..
Thanks
Raj
Instead of relying on the flex tooltip, you may want to add a popup on mouse roll over and deal with it that way, ofcoz you have to deal with the positioning of the popup later on, but I think this will give you a lot of flexibility later on.
Apologies for the vague title. I could not think of a better way to word it in so few words.
Basically, I am creating a custom ItemRenderer (IR). The IR has a label on the left side and an icon on the right side. The icon on the right side is dynamic (can be either an add or remove icon or nothing at all). This works beautifully and gives me the control I need over it.
Now, the problem is that when I scroll the list in my mobile application, the icons change.
How it should look:
How it looks after scrolling using a finger (or mouse in emulator) by dragging on Test3:
As you can see, the icons change but the labels do not. I have dragEnabled, dropEnabled, and dragMoveEnabled all set to false on my Spark List component. The only time the icon selection runs is on creationComplete, so there is no way it is choosing a different icon at some point. I can also verify that the data itself is what it should be after this change occurs.
Here is the MXML that creates the item:
<s:HGroup width="100%" verticalAlign="middle" left="{this.sideSpacing}" right="{this.sideSpacing}" top="{this.sideSpacing}" bottom="{this.sideSpacing}">
<s:Label id="text" width="100%"/>
<s:Image id="actionIcon" buttonMode="true" click="actionIconClick( event );">
<s:filters>
<s:DropShadowFilter alpha=".45" angle="90" distance="3" blurX="3" blurY="3" quality="3"/>
</s:filters>
</s:Image>
</s:HGroup>
<s:Rect width="100%" height="1" bottom="0" alpha=".1">
<s:fill>
<s:SolidColor color="#000000"/>
</s:fill>
</s:Rect>
And the possibly over-elaborate AS3 for selecting which icon should be displayed:
private function creationComplete( e:Event ):void {
if ( this.data.actionIcon != null ) {
this.actionIconType = this.data.actionIcon;
if ( this.data.actionIcon == ACTION_ICON_ADD ) {
this.actionIcon.source = this.addBitmapSource;
}
else if ( this.data.actionIcon == ACTION_ICON_REMOVE ) {
this.actionIcon.source = this.removeBitmapSource;
}
else {
this.actionIcon.source = null;
this.actionIcon.visible = false;
this.actionIcon.includeInLayout = false;
}
}
else {
this.actionIcon.source = null;
this.actionIcon.visible = false;
this.actionIcon.includeInLayout = false;
}
}
What could be causing this issue?
Basically, you need to update your renderer's label and icon when the dataChange event is fired. CreationComplete is only fired once. The list isn't really scrolled, just that the data in the itemRenderers change; causing it to look like things are scrolling. I call this renderer recycling.
Here is a component I created for a mobile app that does what you want. It displays a label and an icon (AKA the Decorator). When scrolling the label and icon are both updated. You can use a very similar approach.
<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
dataChange="onDataChange(event)" alpha=".7" width="100%" cacheAsBitmap="true">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.dotcomit.magondaMaze.managers.BoardDataManager;
import com.dotcomit.magondaMaze.managers.StatManager;
import mx.events.FlexEvent;
[Embed(source="assets/images/chooseLevel/completed78x78.png")]
private var completedImage:Class;
public var statManager :StatManager = StatManager.instance;
protected function onDataChange(event:FlexEvent):void
{
var itemAsXML :XML = data as XML;
var results :String = itemAsXML.#id + '. ' + itemAsXML.#title;
label = results;
if( statManager.isBoardComplete(itemAsXML.#id)){
this.decorator = completedImage;
} else {
this.decorator = null;
}
}
]]>
</fx:Script>
</s:IconItemRenderer>
I'll also add that the IconItemRenderer component--which my code above extends--is designed to do exactly what you need. So, you may not have to re-write the wheel so to speak.
How to maximize a Callout, so that it takes the maximal available space at the screen?
I'm trying to display a ViewNavigator in a Callout and while it works, the displayed View is too narrow:
In the same program I have another Callout and it is wide enough:
The only 2 differences between them is that the latter is attached to a CalloutButton and the latter holds a custom Score component for which I set:
override protected function measure():void {
super.measure();
measuredWidth = Capabilities.screenResolutionX;
measuredHeight = Capabilities.screenResolutionY;
}
I keep staring at the Callout.as code, but can't find a way to trick it to occupy most available space yet.
My custom mxml component is quite simple:
PlayerInfo.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Callout
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
contentBackgroundAppearance="none">
<fx:Script>
<![CDATA[
[Bindable]
public var userid:String;
]]>
</fx:Script>
<s:ViewNavigator
firstView="views.Profile"
firstViewData="{userid}">
<s:navigationContent>
<s:Button label="Close" click="close()" />
</s:navigationContent>
</s:ViewNavigator>
</s:Callout>
Callout extends Container, so you shouldn't have problems setting the width and height to 100%.
Also, in the Callout code there's a method:
/**
* #private
* Force a new measurement when callout should use it's screen-constrained
* max size.
*/
private function invalidateMaxSize():void
{
// calloutMaxWidth and calloutMaxHeight don't invalidate
// explicitMaxWidth or explicitMaxHeight. If callout's max size changes
// and explicit max sizes aren't set, then invalidate size here so that
// callout's max size is applied.
if (!canSkipMeasurement() && !isMaxSizeSet)
skin.invalidateSize();
}
So, try to set the 'explicitMaxWidth' and 'explicitMaxHeight' properties.
I want to put an element into another component (in this case a print template), print it, and then return it to its place. The problem is that when I return it, it has the properties of the print template! Here is a simplified example. When you click print, the label is removed and then returned but when returned it is affected by the padding of the print template! Why? How can I somehow refresh it to its proper properties? I tried all the invalidate... methods and parentChanged() but nothing worked.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="200">
<fx:Script>
<![CDATA[
import spark.components.VGroup;
protected function button1_clickHandler(event:MouseEvent):void {
var printTemplate:VGroup = new VGroup();
printTemplate.paddingTop = 50;
printTemplate.paddingLeft = 30;
printTemplate.addElement(label);
addElement(printTemplate);
validateNow();
// print
removeElement(printTemplate);
addElement(label);
}
]]>
</fx:Script>
<s:Button label="Print" right="0" click="button1_clickHandler(event)"/>
<s:Label id="label" text="This is the label text, it should appear at the top-left."/>
</s:Application>
I would recommend you to have a separate print view-component which has a separate label which you only need to pass the right data.
OK I hacked up a solution. Put this in before adding the label back to its proper place:
var vg:VGroup = new VGroup();
vg.addElement(label);
addElement(vg);
validateNow();
removeElement(vg);
Then it gets the padding from "vg", which has no padding set. Yay. Another little hack to circumnavigate a Flex bug.