Avg. Rating 4.3

Problem

How to create cool popup window with animated shader filter.

Solution

I've created shader filter using PixelBender to add light point on the title bar. And using AnimateFilter add this shader. The light point moves under title bar from the left to the right all the time creating cool metallic effect.

Detailed explanation

Following  you can see the example, you can close the popup and open again (use view source to get source code). It was created using Flash Builder 4 beta 1.

The popup window is extended from spark panel, has close button and uses it's own skin class.

Following you can see part of code of shader filter:

void
    evaluatePixel()
    {
        float2 center = float2(centerX, centerY);
        float2 out_pixel_coord = outCoord();
        float attenuation = 1.0 +
pow(attenuationDelta/pow(distance(out_pixel_coord, center),
attenuationDecay), attenuationSpeed);
        dst = attenuation * sampleNearest(src, out_pixel_coord);
    }

To add this filter I used AnimateFilter and ShaderFilter classes provided by Flex 4.

PopupWindowSkin.mxml 

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
 xmlns:s="library://ns.adobe.com/flex/spark" 
 xmlns:mx="library://ns.adobe.com/flex/halo" 
 width="400" height="300"
 addedToStage="addedToStageHandler(event)" 
 removedFromStage="removedFromStageHandler(event)">

 <fx:Script>
 <![CDATA[
 import mx.events.FlexEvent;

 protected function removedFromStageHandler(event:Event):void
 {
 animatedFilter.stop()
 }

 protected function addedToStageHandler(event:Event):void
 {
 animatedFilter.play();
 }
 ]]>

 </fx:Script>

 <fx:Metadata>
      [HostComponent("views.PopupWindow")]
    </fx:Metadata> 

 <s:layout>

 <s:BasicLayout/>

 </s:layout>

     <s:states>
    <s:State name="normal" />
    <s:State name="disabled" />
    </s:states>

    <fx:Declarations>

 <s:ShaderFilter id="shaderFilter"
 shader="{Shaders.titleEffect}" 
 centerY="-85"  
 attenuationDecay="1.2" 
 attenuationDelta="100" 
 attenuationSpeed="1.34"
 />

 <s:AnimateFilter id="animatedFilter"
 target="{titleGroup}" 
 bitmapFilter="{shaderFilter}" 
 duration="6000" 
 repeatCount="9999" repeatDelay="0">

 <s:SimpleMotionPath valueFrom="-400" 
 valueTo="{width + 400}" 
 property="centerX"
 />

 </s:AnimateFilter>

    </fx:Declarations>

  <!-- drop shadow -->
    <s:Rect left="0" top="0" right="0" bottom="0">
        <s:filters>
            <s:DropShadowFilter blurX="20" blurY="20" 
            alpha="0.32" distance="11" 
            angle="90" knockout="true" 
            />
        </s:filters>
        <s:fill>
            <s:SolidColor color="0" />
        </s:fill>
    </s:Rect>

 <!-- layer 1: border -->
 <s:Rect left="0" right="0" top="0" bottom="0">
 <s:stroke>
 <s:SolidColorStroke color="0" alpha="0.50" weight="1" />
 </s:stroke>
 </s:Rect>

    <!-- layer 2: background fill -->
    <s:Rect id="background" left="1" top="1" right="1"
bottom="1">
        <s:fill>
            <s:SolidColor color="0xFFFFFF" id="bgFill" />
        </s:fill>
    </s:Rect>

    <s:Group id="titleGroup" left="1" right="1" top="1"
height="25">

 <!-- layer 3: title bar fill -->
 <s:Rect left="0" right="0" top="0" height="25">
 <s:fill>
   <mx:SolidColor color="#a6b6b6"/>
         </s:fill>
 </s:Rect>

 <!-- layer 5: text -->
 <s:Label id="titleField" lineBreak="explicit" text="Title"
  left="10" right="26" top="1" height="25"
  verticalAlign="middle" fontWeight="bold"
   fontFamily="Verdana" fontSize="11" color="#1B3822">
 </s:Label> 

 <s:Button id="closeButton" 
 y="4" label="x" right="3" 
 width="27" height="18" 
 skinClass="skins.CloseButtonSkin" 
 />
 </s:Group> 

 <!-- layer 4: title bar highlight -->
    <s:Rect left="1" right="1" top="1" height="25">
       <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0xEAEAEA" />
                <s:GradientEntry color="0xD9D9D9" />
            </s:LinearGradientStroke>
       </s:stroke>
    </s:Rect>

    <s:Rect left="1" right="1" top="26" height="1">
    <s:fill>
    <s:SolidColor color="0xC0C0C0" />
    </s:fill>
    </s:Rect> 

    <s:Group id="contentGroup" left="1" right="1" top="27"
bottom="1">
    </s:Group>
</s:Skin>
CloseButtonSkin.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:s="library://ns.adobe.com/flex/spark" 
 xmlns:fx="http://ns.adobe.com/mxml/2009">
 <s:states>
 <s:State name="up"/>
 <s:State name="over"/>
 <s:State name="down"/>
 <s:State name="disabled"/>
 </s:states>

 <fx:Metadata>[HostComponent("spark.components.Button")]</fx:Metadata>

 <s:Group left="0" right="0" top="0" bottom="0"
alpha.up="0.9">
 <s:filters.over>
 <s:GlowFilter alpha="0.75" blurX="6" blurY="6" color="0xd62b2b"
quality="3"/>
 </s:filters.over>

 <s:Path data="M 32 12.5 C 32 16.919 28.582 20.5 24.364 20.5 L
8.136 20.5 
               C 3.918 20.5 0.5 16.919 0.5 12.5 L 0.5 8.5 C 0.5
4.082 3.918 0.5 8.136 0.5 
               L 24.364 0.5 C 28.582 0.5 32 4.082 32 8.5 L 32 12.5
Z" 
               left="1" right="1" top="1" bottom="1">
 <s:fill>
 <s:LinearGradient rotation="90">
 <s:GradientEntry color.down="0xd87660" color="0xf8a690"
ratio="0.0933368"/>
 <s:GradientEntry color.down="0xd87660" color="0xf06950"
ratio="0.392417"/>
 <s:GradientEntry color.down="0xc81812" color="0xe82822"
ratio="0.874426"/>
 <s:GradientEntry color.down="0xd05b4f" color="0xf06b5f"
ratio="1"/>
 </s:LinearGradient>
 </s:fill>
 <s:stroke>
 <s:SolidColorStroke color="0x555555" />
 </s:stroke>
 </s:Path>

 <s:Path  data="M 9.527 0.502 L 12.918 0.5 L 8.407 5.229 L
12.918 9.957 L 9.525 9.957 
 L 6.728 7.001 L 3.93 9.955 L 0.522 9.957 L 5.05 5.228 L 0.522 0.5 
 L 3.933 0.5 L 6.729 3.456 L 9.527 0.502 Z" 
 horizontalCenter="0" verticalCenter="0" width="40%"
height="50%">
 <s:stroke>
 <s:SolidColorStroke color="0xffffff" />
 </s:stroke>
 <s:fill>
 <s:SolidColor color="0xffffff"/>
 </s:fill>
 </s:Path>

 </s:Group>
</s:Skin>

 PopupWindow.as

package views

{
import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.utils.describeType;
import mx.core.FlexGlobals;
import mx.managers.PopUpManager;
import skins.PopupWindowSkin;
import spark.components.Button;
import spark.components.Panel;

/**
 *  Base class for popup windows.
 * 
 */ 
public class PopupWindow extends Panel

{
 /**
     *  Constructor. 
     *  
     */  
 public function PopupWindow()

 {
 setStyle("skinClass", PopupWindowSkin);
 }

 [SkinPart(required="false")]
  /**
     *  The skin part that defines the appearance of the 
     *  close button.
     *
     */
 public var closeButton:Button;

 /**
     *  Open popup window and center it.
     */
 public function open():void
 {
 PopUpManager.addPopUp(this, FlexGlobals.topLevelApplication as
DisplayObject,true);
 PopUpManager.centerPopUp(this);
 }

 /**
     *  Close popup window.
     */
 public function close():void
 {
 PopUpManager.removePopUp(this);
 }

 /**
     *  @private
     */
 override protected function partAdded(partName:String,
instance:Object) : void
 {
 if(instance == closeButton)
 {
 closeButton.addEventListener(MouseEvent.CLICK, closeHandler);
 }
 super.partAdded(partName, instance);
 }

 /**
     *  @private
     */
 protected function closeHandler(event:MouseEvent):void
 {
 close();
 }

 /* Fixing bug with extending with SkinParts */     
 // this bug should be fixed in further version of flex 4 sdk.
 protected override function findSkinParts() : void
 {
 repairSkinParts();
 super.findSkinParts();
 }

 /**
     *  @private
     */
 protected function repairSkinParts():void
 {
 var desc:XML = describeType(this);
 for each (var variable:XML in desc.elements("variable"))
 {
 var varName:String = variable.@name;
 for each (var metadata:XML in variable.elements("metadata"))
 {
 var metaName:String = metadata.@name;
 if (metaName == "SkinPart")
 {
 for each (var arg:XML in metadata.elements("arg"))
 {
 var required:Boolean = false;
 if (arg.@key == "required")
 if (arg.@value == "true")
 required = true;
 }
 skinParts[varName] = required;
 }
 }
 }
 }
 /* Ending fixing bug with extending with SkinParts */
}
}

For more information please visit my blog.


+
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

Report abuse

Related recipes