apply animation to UI component via actionscript in flex issue - apache-flex

Here is my entire application. Pretty easy stuff.
I have two panels that have a click event on them. However, both call the same function for some reason. When I have only one panel visible the animation works correctly. However if I add another to the stage on the click event both panels animate at the same time.
I just dont get what I'm doing wrong. My function is looking for only the current target but apparently I must not be doing that correctly because it's animating both panels and not just the panel the I clicked. My expected result is to animate only the clicked panel.
Any help would be really appreciated.
<?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"
applicationComplete="application1_applicationCompleteHandler(event)"
left="20">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<!--<s:Sequence id="EffectsHide">-->
<!--<s:Rotate id="rotatein" target="{panel1}" angleBy="90"/>-->
<mx:Parallel id="EffectsHide">
<s:Rotate3D angleYFrom="0" angleYTo="360" duration="1000" />
<s:Resize id="shrink" duration="1000" heightBy="-170" />
<s:Move3D id="MoveIn" yBy="{_applicationHeighth-30}" duration="1000"/>
</mx:Parallel>
<!-- </s:Sequence>-->
<s:Sequence id="EffectsShow">
<s:Rotate id="rotateOut" target="{panel1}" angleBy="-90"/>
<s:Move id="MoveOUt" target="{panel1}" xBy="-30"/>
<s:Resize id="grow" target="{panel1}" duration="2000" widthBy="{_applicationWidth}" heightBy="{_applicationHeighth}"/>
</s:Sequence>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.effects.Effect;
import mx.effects.Parallel;
import mx.events.FlexEvent;
private var myParallel:Parallel = new Parallel();
private var myParallelReverse:Parallel = new Parallel();
[Bindable]
public var _applicationWidth:Number = new Number();
[Bindable]
public var _applicationHeighth:Number = new Number();
[Bindable]
public var Maximized :Boolean = true;
public var minimized :Boolean = false;
public function rotateTarget(event:Event):void{
//define the rotate effect
/*
var myRotated3d:Rotate3D= new Rotate3D(event.currentTarget);
myRotated3d.angleYFrom = 0;
myRotated3d.angleYTo=360;
myRotated3d.duration=1000;
*/
if(Maximized == true)
{
//EffectsHide.target(_target);
//EffectsHide.stop();
//EffectsHide.play();
//var myRotated3d:Rotate3D= new Rotate3D(event.currentTarget);
//myRotated3d.angleYFrom = 0;
//myRotated3d.angleYTo=360;
//myRotated3d.duration=1000
var myResize:Resize = new Resize(event.currentTarget);
myResize.heightBy = -160;
myResize.duration = 500;
var myMove3D:Move= new Move(event.currentTarget);
myMove3D.yTo=_applicationHeighth-30;
myMove3D.duration=500;
//myParallel.addChild(myRotated3d);
myParallel.addChild(myResize);
myParallel.addChild(myMove3D);
//this.invalidateDisplayList();
//this.validateNow();
//this.panel1.validateProperties();
minimized= true;
Maximized = false;
myParallel.stop();
myParallel.play();
trace('tried to run')
}
else if (Maximized == false){
trace(numElements)
//trace(getElementIndex(panel1));
//var myRotated3drever:Rotate3D= new Rotate3D(event.currentTarget);
//myRotated3drever.angleYFrom = 0;
//myRotated3drever.angleYTo=-360;
//myRotated3drever.duration=1000;
var myResizerever:Resize = new Resize(event.currentTarget);
myResizerever.heightTo= 200;
myResizerever.duration =500;
var myMove3Drever:Move = new Move(event.currentTarget);
myMove3Drever.yTo=(0);
myMove3Drever.duration=500;
myParallelReverse.addChild(myMove3Drever);
myParallelReverse.addChild(myResizerever);
//myParallelReverse.addChild(myRotated3drever);
myParallelReverse.play();
Maximized = true;
}
}
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
_applicationWidth = stage.width;
_applicationHeighth = stage.height;
}
protected function _butt_clickHandler(event:MouseEvent):void
{
trace(panel1.x);
trace(panel1.y);
trace(panel1.height);
}
]]>
</fx:Script>
enter code here
<mx:Canvas>
<mx:Panel id="panel1" title="Label1" x="400" y="0" width="200" height="200" click="rotateTarget(event)"/>
<mx:Panel id="panel2" title="Label2" x="0" y="0" width="200" height="200" click="rotateTarget(event)"/>
</mx:Canvas>
<!--<s:Panel id="panel2" y="240" title="Label2" width="200" height="200" click="rotateTarget(event)"/>
-->
<!--</s:VGroup>-->
<s:Button x="250" id="_butt" click="_butt_clickHandler(event)"/>
<s:Button x="250" y="20" id="_butt2" click="rotateTarget(event)"/>
</s:Application>

My two best guess without the full code (the bit with the panels):
You should be using event.target rather than event.currentTarget.
You bound the 'EffectsHide' (all IDs should be lowercase by the way) parallel directly to 'panel1' so whenever it gets plays that is the component it is going to target.
*I see now that you keep adding new animation effects created in the rotatetarget function to the parallel 'myParallel'. You do not however remove them at any given point so it just keeps on playing all the effects you ever added to it each time it get's played. You should just add them once on application setup and then just play them.

Related

Handling mouse click in Flex 4 List to find the selected item (since itemClick is gone)

I have prepared a simplified test case for my question. It will run instantly in your Flash Builder if you put the 2 files below into a project.
I'm trying to display a List of strings and a confirmation checkbox in a popup:
In the real application I dispatch a custom event with the string selected in the list, but in the test code below I just call trace(str);
My problem: if I use click event, then the window closes, even if I click at a scrollbar (the !str check below doesn't help, when an item had been selected in previous use). And if I use change event, then the window doesn't close, when I click on the same item as the last time. And the itemClick event seems not to be present in spark.components.List anymore.
Any suggestions please on how to handle this probably frequent problem?
Writing a custom item renderer and having a click event handler for each item seems to be overkill for this case, because I have strings in the list.
Test.mxml: (please click myBtn few times - to see my problems with click and change)
<?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="400" minHeight="300">
<fx:Script>
<![CDATA[
import mx.managers.PopUpManager;
private var _popup:Popup = new Popup();
private function showPopup(event:MouseEvent):void {
PopUpManager.addPopUp(_popup, this, true);
PopUpManager.centerPopUp(_popup);
}
]]>
</fx:Script>
<s:Button id="myBtn" right="5" bottom="5"
label="Open window" click="showPopup(event)" />
</s:Application>
Popup.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow
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="240" height="240"
creationComplete="init(event)"
close="close()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.events.CloseEvent;
import mx.events.ItemClickEvent;
import mx.managers.PopUpManager;
private var myData:ArrayList = new ArrayList();
private function init(event:FlexEvent):void {
// XXX in the real app data is updated from server
myData.removeAll();
for (var i:uint = 1; i <= 10; i++)
myData.addItem('Item #' + i);
}
public function close(event:TimerEvent=null):void {
PopUpManager.removePopUp(this);
}
private function handleClick(event:MouseEvent):void {
var str:String = myList.selectedItem as String;
if (!str)
return;
if (myBox.selected) {
Alert.show(
'Select ' + str + '?',
null,
mx.controls.Alert.YES | mx.controls.Alert.NO,
null,
handleConfirm,
null,
mx.controls.Alert.NO
);
} else {
sendEvent();
}
}
private function handleConfirm(event:CloseEvent):void {
if (event.detail == mx.controls.Alert.YES)
sendEvent();
}
private function sendEvent():void {
close();
// XXX in the real app dispatchEvent() is called
trace('selected: ' + (myList.selectedItem as String));
}
]]>
</fx:Script>
<s:VGroup paddingLeft="20" paddingTop="20"
paddingRight="20" paddingBottom="20" gap="20"
width="100%" height="100%">
<s:List id="myList" dataProvider="{myData}"
click="handleClick(event)"
width="100%" height="100%" fontSize="24" />
<s:CheckBox id="myBox" label="Confirm" />
</s:VGroup>
</s:TitleWindow>
Also I wonder, why do I get the warning above:
Data binding will not be able to detect assignments to "myData".
The Spark List dispatches an 'IndexChangeEvent.CHANGE'. You can listen for this event to know when the selection in the List has changed.
<s:List id="myList" dataProvider="{myData}"
change="handleIndexChange()"
width="100%" height="100%" fontSize="24" />
That event is only dispatched whenever the selected index actually changes, which means that when you reopen the window a second time an item might still be selected and when you click on that one, no CHANGE event will be fired. To fix this just deselect the selection before you close the window:
public function close():void {
myList.selectedIndex = -1;
PopUpManager.removePopUp(this);
}
Also make sure to dispatch your event with the selected item before you close the window (and deselect it).
As for your question about the binding warning: you get that message because you didn't mark 'myData' to be bindable. To fix this just use the [Bindable] tag:
[Bindable]
private var myData:ArrayList = new ArrayList();
or skip the binding altogether if you don't need it and just assign the dataprovider to the list in ActionScript:
myList.dataProvider = myData;
I'd recommend two solutions if you absolutely wnat to display what item was selected. Otherwise, the solution provided by RIAStar would do the trick.
Listen to rendererAdd and rendererRemove events within your PopUp
As explained here, you can easily access to your list's renderers without interfering with its virtualLayout business.
Use a custom renderer
I know. But as long as you keep your code clean, itemRenderers won't blow up your application's memory. They're made to render huge amount of items without memory leaks.
In your Test.mxml, modify the codes like:
<fx:Script>
<![CDATA[
import mx.managers.PopUpManager;
private var _popup:Popup;
private function showPopup(event:MouseEvent):void {
_popup = new Popup();
PopUpManager.addPopUp(_popup, this, true);
PopUpManager.centerPopUp(_popup);
}
]]>
</fx:Script>
And in your Popup.mxml, I am not sure why you have the TimerEvent in the close function.
Also the trace won't be shown, as you are calling the close() function immediately after the alert's YES button has been clicked..

webstageview not loading on phone but working in emulator

I'm trying to get a webstageview to load a local html file....this code works perfectly on the emulator, but when i run it on my android device (running android 2.3), it does not work....it just creates a blank webstageview that never loads the local html file...the zoom function is intact so i know it's opening the webstageview, but i never see the content....any advice? i am stuck...
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:ns1="*"
xmlns:controls="com.flexcapacitor.controls.*"
actionBarVisible="false" backKeyPressed="onBackKeyPressed(event)"
creationComplete="view1_creationCompleteHandler(event)" title="{data.image}"
xmlns:components="com.flexcapacitor.components.*">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import spark.components.ViewNavigator;
public var webView1:StageWebView=new StageWebView();
protected function view1_creationCompleteHandler(event:FlexEvent):void
{
webView1.stage=this.stage;
webView1.viewPort=new Rectangle(0,50,stage.stageWidth, stage.stageHeight);
var fPath:String=new File(new File("app:/"+data.html).nativePath).url;
webView1.loadURL(fPath);
}
protected function onBackKeyPressed(event:FlexEvent):void{
webView1.viewPort = null;
webView1.dispose();
webView1 = null;
}
protected function backbutton_clickHandler(event:MouseEvent):void
{
webView1.viewPort = null;
webView1.dispose();
webView1 = null;
navigator.popView();
}
]]>
</fx:Script>
<s:Button id="backbackbutton" x="0" y="0" width="100%" height="50" label="Back" click="backbutton_clickHandler(event)"/>
i ended up having to make some temporary files to open it properly....not sure why it wouldn't work before even though the emulator worked fine...here's the code that works:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:ns1="*"
xmlns:controls="com.flexcapacitor.controls.*"
actionBarVisible="false" backKeyPressed="onBackKeyPressed(event)"
creationComplete="view1_creationCompleteHandler(event)" title="{data.image}"
xmlns:components="com.flexcapacitor.components.*">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import spark.components.ViewNavigator;
public var webView1:StageWebView=new StageWebView();
protected function view1_creationCompleteHandler(event:FlexEvent):void
{
webView1.stage=this.stage;
webView1.viewPort=new Rectangle(0,50,stage.stageWidth, stage.stageHeight);
var fa:File = File.applicationDirectory.resolvePath(data.html);
var f2a:File = File.createTempDirectory();
var fb:File = File.applicationDirectory.resolvePath(data.location);
fa.copyTo(f2a.resolvePath(data.html),true);
fb.copyTo(f2a.resolvePath(data.location),true);
webView1.loadURL(f2a.url + File.separator +data.html);
}
protected function onBackKeyPressed(event:FlexEvent):void{
webView1.viewPort = null;
webView1.dispose();
webView1 = null;
}
protected function backbutton_clickHandler(event:MouseEvent):void
{
webView1.viewPort = null;
webView1.dispose();
webView1 = null;
navigator.popView();
}
]]>
</fx:Script>
<s:Button id="backbackbutton" x="0" y="0" width="100%" height="50" label="Back"
accentColor="#000000" chromeColor="#404040" click="backbutton_clickHandler(event)"
color="#FFFFFF"/>
Did you add your 'app' folder to your build path so the html file is included in your release build? If not, right click on your project and go to properties > Actionscript Build Path > Source Path > Add Folder...

Panels creation at runtime can't see them

My problem is i am trying to make a panel. My button in in Main.mxml whereas the panel functions are defined in panel_Create.mxml. the code works fine. In panel_Create their are functions to create panels at runtime. The problem i am facing is when i run the program it wont show the panels but it does increase the value of n and after 8 clicks it gives alert message. Please tell me why cant i see panels. The code works fine when i put all the code in Main.mxml
<fx:Script>
<![CDATA[
import Components.panel_Create;
import mx.controls.Alert;
import spark.components.Button
public var adminPanel:panel_Create = new panel_Create();
public var n:Number = 0;
public function panel(event:MouseEvent): void
{
if ( n < 8)
{
adminPanel.panel_Create(n);
n++;
}
else
Alert.show('More Panels Not Allowed', 'Alert Box', mx.controls.Alert.OK);
}
]]>
</fx:Script>
<s:Button id="add" includeIn="State1" x="398" y="10" label="Add Panel" click="panel(event)"/>
<Components2:panel_Create includeIn="State1" x="10" y="66" width="737" height="599">
</Components2:panel_Create>
</s:Application>
I believe that the 8 panels are created and based on the code in one of your comments they are added as child elements to the adminPanel.
The problem is that your adminPanel is never added to the stage so is not visible.
Try this instead:
<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">
<fx:Script>
<![CDATA[
private var panels:Array = [];
private function addPanel():void
{
if (panels.length < 8)
{
var panel:Panel = new Panel();
panel.title = "Panel "+(panels.length + 1);
panels.push(panel);
addElement(panel);
}else{
trace('More Panels Not Allowed');
}
}
]]>
</fx:Script>
<s:Button label="Add Panel" click="addPanel()"/>
</s:Application>
adminPanel is not being created. you have to do addElement(adminPanel) itself
if ( n < 8)
{
adminPanel.panel_Create(n);
addElement(adminPanel)
n++;
}

Flex selectedItem problems

I have encountered somthing a little strange in flex, possibly somthing im doing wrong
but im not sure.
In two cases which i have noticed, when there is only 1 item in a s:List or s:DropDownList
for some reason when using list.selectedItem it appears as null. Using requireSelection="true"
i know this isnt the case.
Has anyone else seen anything similar? or am i doing it completly wrong?
Thanks
Jon
Edit: In the code bellow it happens when clicking the edit document, which calls the open edit method
------------ Added Code ---------------------------
I have removed small portions to make it more readable
<s:TitleWindow width="486" height="300" title="Document Store"
xmlns:tmsbean="services.tmsbean.*"
close="close()">
<fx:Declarations>
<s:CallResponder id="getAllAttachedDocumentsResult"/>
<tmsbean:TMSBean id="tMSBean" showBusyCursor="true"/>
<s:CallResponder id="removeDocumentLinkResult" result="getDocumentList()"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
private static var documentStoreView:DocumentStoreView = null;
[Bindable]
private var attachedToMenomic:String;
public static function getInstance():DocumentStoreView
{
if(documentStoreView == null){
documentStoreView = new DocumentStoreView();
DocumentForm.getInstance().addEventListener(DocumentFormEvent.DOCUMENT_ATTACHED,documentStoreView.getDocumentList);
}
return documentStoreView;
}
public function open(menomic:String,parent:DisplayObject):void
{
attachedToMenomic = menomic;
getDocumentList();
PopUpManager.addPopUp(documentStoreView,parent,true);
PopUpManager.centerPopUp(documentStoreView);
y = y - 80;
}
public function close():void
{
PopUpManager.removePopUp(documentStoreView);
}
private function getDocumentList(evt:DocumentFormEvent = null):void
{
getAllAttachedDocumentsResult.token = tMSBean.getAllAttachedDocuments(attachedToMenomic);
}
private function openEdit():void{
var editDsi:DocumentStoreItem = documentList.selectedItem as DocumentStoreItem;
Alert.show(editDsi.documentName);
DocumentForm.getInstance().openInEditMode(editDsi,this);
}
]]>
</fx:Script>
<s:VGroup left="10" top="10" right="10" bottom="10">
<s:List width="100%" height="100%" id="documentList" itemRenderer="com.documentStore.DocumentItemListRenderer"
dataProvider="{Utilitys.toArrayCollection(getAllAttachedDocumentsResult.token.result)}" />
<s:HGroup horizontalAlign="right" width="100%">
<s:Button label="Attach Document" click="{DocumentForm.getInstance().open(attachedToMenomic,this)}"/>
<s:Button label="Edit Document" click="openEdit()"/>
</s:HGroup>
</s:VGroup>
</s:TitleWindow>
By default Spark's DropDownList displays a prompt if selectedIndex is -1, which will be the case if requireSelection is false and you have not otherwise set the list to a specific item. This would correspond with selectedItem being null.
The Spark ComboBox does something similar but it has a TextInput as you can type into it.

I cannot figure out how to access items by their ID if I create them dynamically

In one area of my application I am creating a display that builds itself with actionscript during a loop. (in my actual app there are A LOT of nested children and my function might be looking for any of those children) In that AS I assign each item an ID, but when I try to access that item by it's id it fails. What gives? and how can I accomplish finding a UI component without having to go through knowing all of it's possible parents?
Here's a simplified example of what I'm doing. The button click will fail with an error
ReferenceError: Error #1069: Property myPanel3 not found on Test and there is no default value.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init();">
<mx:Script>
<![CDATA[
import mx.containers.Panel;
private function init():void{
var i:uint = 0;
for(i = 0; i<10; i++){
var loopPanel:Panel = new Panel;
loopPanel.title = i.toString();
loopPanel.id = "myPanel" + i.toString();
myVBox.addChild(loopPanel);
}
}
private function clicked():void{
var tracePanel:Panel = this["myPanel3"];
trace(tracePanel);
}
]]>
</mx:Script>
<mx:VBox id="myVBox" x="10" y="10" width="500"/>
<mx:Button id="myBtn" x="518" y="8" label="Click Me" click="clicked();"/>
</mx:Application>
Try this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init();">
<mx:Script>
<![CDATA[
import mx.containers.Panel;
private function init():void{
var i:uint = 0;
for(i = 0; i<10; i++){
var loopPanel:Panel = new Panel;
loopPanel.title = i.toString();
loopPanel.name = "myPanel" + i.toString();
myVBox.addChild(loopPanel);
}
}
private function clicked():void{
var tracePanel:DisplayObject = myVBox.getChildByName("myPanel3");
trace(tracePanel.name);
}
]]>
</mx:Script>
<mx:VBox id="myVBox" x="10" y="10" width="500"/>
<mx:Button id="myBtn" x="518" y="8" label="Click Me" click="clicked();"/>
Changes on two lines:
loopPanel.name = "myPanel" + i.toString();
and
var tracePanel:DisplayObject = myVBox.getChildByName("myPanel3");
Nesting - you should probably create a dictionary (eg. assocative array with "name" - "object reference" pairs) of your custom objects if you need to access them without searching in subcomponents.

Resources