Modal window animation disrupted when calling PopUpManager.removePopUp() from inside pop up

StackOverflow https://stackoverflow.com/questions/21113068

  •  27-09-2022
  •  | 
  •  

質問

I have a modal window I'm displaying with a resize animation on open and close but sometimes it flickers on close.

I've tracked it down to one thing. When I click outside of the window the close animation plays fine. The code is in the main application and is in mouseUpOutsideHandler method. It's a simple call to PopUpManager.removePopUp(). When I click the close button that's inside of the window it runs the same exact code PopUpManager.removePopUp() in the close() method inside the window except it flickers first.

It's the same exact code except it's called from within the modal window instance. It looks like the modal window is getting faded out and then removed and then my remove animation is played. See code example.

Example:

<?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 com.flexcapacitor.effects.popup.OpenPopUp;

        import mx.core.IFlexDisplayObject;
        import mx.managers.PopUpManager;

        protected function showPopUp():void {
            var myPopUp:MyPopUp = new MyPopUp();
            PopUpManager.addPopUp(myPopUp as IFlexDisplayObject, this, true);
            PopUpManager.centerPopUp(myPopUp);

            myPopUp.addEventListener(OpenPopUp.MOUSE_DOWN_OUTSIDE, mouseUpOutsideHandler, false, 0, true);
        }

        private function mouseUpOutsideHandler(event:Event):void {
            // does not create a flicker
            PopUpManager.removePopUp(event.currentTarget as IFlexDisplayObject);
            MyPopUp(event.currentTarget).removeEventListener(OpenPopUp.MOUSE_DOWN_OUTSIDE, mouseUpOutsideHandler);  
        }

    ]]>
</fx:Script>


<fx:Declarations>
    <fx:Component className="MyPopUp">
        <s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx" 
           resizeEffect="Resize"
           resize="panel1_resizeHandler(event)"
           creationCompleteEffect="{addedEffect}"
           removedEffect="{removedEffect}"
           width="400" height="200">

            <fx:Script>
                <![CDATA[
                    import mx.events.ResizeEvent;
                    import mx.managers.PopUpManager;


                    protected function close():void {
                        // when called here creates a flicker effect 
                        // it looks like the pop up is faded out and removed 
                        // and then the removed effect is played
                        PopUpManager.removePopUp(this);
                    }

                    protected function panel1_resizeHandler(event:ResizeEvent):void {
                        if (stage && !addedEffect.isPlaying) {
                            PopUpManager.centerPopUp(this);
                        }
                    }
                ]]>
            </fx:Script>

            <fx:Declarations>
                <s:Parallel id="removedEffect" target="{this}" >
                    <s:Scale3D scaleYTo="0" duration="1000" startDelay="0" disableLayout="false"
                               autoCenterProjection="true" autoCenterTransform="true"/>
                    <s:Fade alphaFrom="1" alphaTo="0" duration="500" startDelay="50"/>
                </s:Parallel>

                <s:Parallel id="addedEffect" target="{this}" >
                    <s:Scale3D scaleYFrom="0" scaleYTo="1" duration="250" disableLayout="false"
                               autoCenterProjection="true" autoCenterTransform="true"/>
                    <s:Fade alphaFrom="0" alphaTo="1" duration="200"/>
                </s:Parallel>

            </fx:Declarations>

            <s:Label horizontalCenter="0" verticalCenter="0" text="Hello World"/>
            <s:Button horizontalCenter="0" verticalCenter="30" label="Close" click="close()"/>
        </s:Panel>
    </fx:Component>
</fx:Declarations>


<s:Button label="Show Pop Up" 
          horizontalCenter="0" verticalCenter="0"
          click="showPopUp()" 
          />

役に立ちましたか?

解決

It can be fixed by using call later.

METHOD 1

protected function close():void {
      //PopUpManager.removePopUp(this);
      callLater(PopUpManager.removePopUp, [this]);
}

METHOD 2

function close(popUp:IFlexDisplayObject, endEffectsPlaying:Boolean = true) {
    if (popUp && popUp as IUIComponent && UIComponent(popUp).isEffectStarted) {
        if (endEffectsPlaying && popUp && popUp as IUIComponent) {
            EffectManager.endEffectsForTarget(popUp as IUIComponent);
        }

        // we exit out because if we continue, we would close the pop up.
        // but if we did that then when the effect ends it puts up a 
        // display object "shield" and there would be no way to close 
        // the display object shield since we removed the pop up 
        // display object that has our closing event listeners 
        return;
    }

    try {
        PopUpManager.removePopUp(popUp as IFlexDisplayObject);

    }
    catch (error:Error) {
        // sometimes the pop up is already closed or something 
        // or there's a bug in PopUpManager or EffectManager
    }
}

BONUS CODE

// The following code may be unrelated but it was
// in my pop up so it might be helping prevent an error
// i normally don't add unrelated code but it may help
protected function panel1_resizeHandler(event:ResizeEvent):void {
    if (stage && !addedEffect.isPlaying) {
        // to fix bug on line 505 of PopUpManagerImpl
        var popUpImp:PopUpManagerImpl = PopUpManagerImpl(Singleton.getInstance("mx.managers::IPopUpManager"));
        var popupInfo:Array = popUpImp.popupInfo;

        const n:int = popupInfo.length;
        var instanceIndex:int = -1;

        for (var i:int = 0; i < n; i++) {
            var o:PopUpData = popupInfo[i];
            if (o.owner == this) {
                instanceIndex = i;
            }
        }

        if (instanceIndex!=-1) {
            PopUpManager.centerPopUp(this);
        }
    }
}

Also, you can see if the OpenPopUp and ClosePopUp effects class works for you.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top