Flex Mobile Development: Creating Dialog Windows

Ever wondered how to create a modal dialog window in Flex mobile applications? For example, you may want to ask the user for a confirmation when he performs a delete operation or maybe to select an item from a list. Well, if you don’t know how to do it, then read on.

Flex has a class that just does this: SkinnablePopUpContainer. SkinnablePopUpContainer extends SkinnableContainer class and has a very simple API you can use in order to “open” and “close” the dialog.

Understanding SkinnablePopUpContainer

Because SkinnablePopUpContainer extends the SkinnableContainer it is extremely easy to create any kind of dialog window you want. You can create a new MXML component that extends the SkinnablePopUpContainer. Then you set a layout manager that works for you (VerticalLayout, HorizontalLayout). And finally, you add the UI components you need – labels, buttons, lists, and so on.

Suppose you want to create a simple alert window that looks like this:

Here is the code to implement this (as a new MXML component that extends SkinnablePopUpContainer):

<?xml version="1.0" encoding="utf-8"?>
<s:SkinnablePopUpContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    backgroundColor="0x898989">

    <s:layout>
        <s:VerticalLayout horizontalAlign="center"/>
    </s:layout>

   <s:Label text="The contact was saved" width="100%" textAlign="center"/>
   <s:Button label="OK" width="100%" click="this.close()"/>
</s:SkinnablePopUpContainer>

The API for controlling the SkinnablePopUpContainer is pretty simple:

Here is an example of how to open a SkinnablePopUpContainer component and read the flag/data when it is closed:

//create the component and open it
var alertWindow:SkinnablePopUpContainer = new SkinnablePopUpContainer();
alertWindow.addEventListener(PopUpEvent.CLOSE, onAlertClose, false, 0, true);
alertWindow.width = stage.width;
alertWindow.height = stage.height / 2;
alertWindow.x = 0;
alertWindow.y = 100;
alertWindow.open(this, true);

private function onAlertClose(event:PopUpEvent):void {
    trace(event.commit);
    trace(event.data);
    alertWindow = null;
}

Creating custom dialog windows

Once you understand how to use the SkinnablePopUpContainer it is pretty simple to create any kind of dialog window you might need: confirmation messages, simple alerts, pop up lists, and so on. Here is the code for a confirmation window that has two buttons (Yes and No) and lets you set the message text:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <s:SkinnablePopUpContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
  3.                                                    xmlns:s="library://ns.adobe.com/flex/spark"
  4.                                                    backgroundColor="0×898989" width="400">
  5.         <s:layout>
  6.                 <s:VerticalLayout gap="20" paddingBottom="10" paddingLeft="30" paddingRight="30" paddingTop="30" horizontalAlign="center"/>
  7.         </s:layout>
  8.         <fx:Script>
  9.                 <![CDATA[
  10.                        
  11.                         private var _message:String;
  12.                        
  13.                         [Bindable]
  14.                         public function get message():String {
  15.                                 return _message;
  16.                         }
  17.  
  18.                         public function set message(value:String):void {
  19.                                 _message = value;
  20.                         }
  21.  
  22.                         private function onClick(commit:Boolean):void {
  23.                                 super.close(commit);                           
  24.                         }
  25.                        
  26.                 ]]>
  27.         </fx:Script>
  28.        
  29.         <s:Label text="{message}" width="100%" textAlign="center"/>
  30.  
  31.         <s:HGroup width="100%">
  32.                 <s:Button label="Yes" width="50%" click="onClick(true)"/>
  33.                 <s:Button label="No" width="50%" click="onClick(false)"/>
  34.         </s:HGroup>
  35.        
  36. </s:SkinnablePopUpContainer>

And here is how this component look on my Android phone:

And here is the code for a pop up list that lets you to set the title, the list’s data provider, the list’s label field, the list’s initial selected items, and multiple selections (you can retrieve the selected items by listening for PopupEvent.CLOSE and reading the data attribute).

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <s:SkinnablePopUpContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
  3.                                                    xmlns:s="library://ns.adobe.com/flex/spark"
  4.                                                    backgroundColor="0×898989" width="400">
  5.         <s:layout>
  6.                 <s:VerticalLayout gap="20" paddingBottom="10" paddingLeft="30"
  7.                                                   paddingRight="30" paddingTop="30" horizontalAlign="center"/>
  8.         </s:layout>
  9.         <fx:Script>
  10.                 <![CDATA[
  11.                         import mx.collections.ArrayCollection;
  12.                        
  13.                         private var _dataProvider:ArrayCollection;
  14.                         private var _labelField:String;
  15.                         private var _allowMultipleSelection:Boolean;
  16.                         private var _selectedItems:Vector.<Object>;
  17.                        
  18.                         [Bindable]
  19.                         public function get selectedItems():Vector.<Object> {
  20.                                 return _selectedItems;
  21.                         }
  22.  
  23.                         public function set selectedItems(v:Vector.<Object>):void {
  24.                                 _selectedItems = v;
  25.                         }
  26.  
  27.                         [Bindable]
  28.                         public function get allowMultipleSelection():Boolean {
  29.                                 return _allowMultipleSelection;
  30.                         }
  31.  
  32.                         public function set allowMultipleSelection(v:Boolean):void {
  33.                                 _allowMultipleSelection = v;
  34.                         }
  35.  
  36.                         [Bindable]
  37.                         public function get labelField():String {
  38.                                 return _labelField;
  39.                         }
  40.  
  41.                         public function set labelField(v:String):void {
  42.                                 _labelField = v;
  43.                         }
  44.                        
  45.                         [Bindable]
  46.                         public function get dataProvider():ArrayCollection {
  47.                                 return _dataProvider;
  48.                         }
  49.  
  50.                         public function set dataProvider(v:ArrayCollection):void {
  51.                                 _dataProvider = v;
  52.                         }
  53.                        
  54.                         private function onClick(commit:Boolean):void {
  55.                                 super.close(commit, list.selectedItems);                               
  56.                         }
  57.                 ]]>
  58.         </fx:Script>
  59.        
  60.         <s:Label text="Select an item:" width="100%"/>
  61.        
  62.         <s:List id="list" width="100%" height="100%"
  63.                         dataProvider="{dataProvider}"
  64.                         labelField="{labelField}"
  65.                         allowMultipleSelection="{allowMultipleSelection}"
  66.                         selectedItems="{selectedItems}"/>
  67.                
  68.         <s:HGroup width="100%">
  69.                 <s:Button label="OK" width="50%" click="onClick(true)"/>
  70.                 <s:Button label="Cancel" width="50%" click="onClick(false)"/>
  71.         </s:HGroup>
  72.        
  73. </s:SkinnablePopUpContainer>

And here is the component running on my phone:

Skinning

The two custom dialog windows I showed you in the previous section use the default look and feel. What about skinning a SkinnablePopUpContainer? There is a Flex class that provides the default skin for a SkinnablePopUpContainer: SkinnablePopUpContainerSkin. By creating a skin that extends this default skin you can change the background of the component quite easily. If you look at the SkinnablePopUpContainerSkin skin you’ll notice that it has a rect with the id equal to background. This is the starting point to change the default background. You can draw additional stuff on top of this background or replace it alltogether with an FXG or PNG file.

For the rest of the UI components used in a SkinnablePopUpContainer (buttons, text inputs, labels, and so on) you will create additional skins and/or use CSS. Here is a screenshot with the same confirmation window but this time using a custom skin:

Here is the skin class used to customize the confirmation window presented in the previous section:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
  3.         xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
  4.                 alpha.disabled="0.5" xmlns:skins="org.corlan.dialog.skins.*">
  5.    
  6.     <fx:Metadata>
  7.     <![CDATA[
  8.         /**
  9.          * @copy spark.skins.spark.ApplicationSkin#hostComponent
  10.          */
  11.         [HostComponent("spark.components.SkinnablePopUpContainer")]
  12.     ]]>
  13.     </fx:Metadata>
  14.    
  15.     <s:states>
  16.         <s:State name="normal"/>
  17.         <s:State name="disabled"/>
  18.         <s:State name="closed" stateGroups="closedGroup"/>
  19.         <s:State name="disabledAndClosed" stateGroups="closedGroup"/>
  20.     </s:states>
  21.    
  22.     <!– Transitions for open and close –>
  23.     <s:transitions>
  24.         <s:Transition fromState="closed" toState="normal" autoReverse="true">
  25.             <s:Fade duration="150" target="{chrome}"/>
  26.         </s:Transition>
  27.  
  28.         <s:Transition fromState="disabledAndClosed" toState="disabled" autoReverse="true">
  29.             <s:Fade duration="150" target="{chrome}"/>
  30.         </s:Transition>
  31.        
  32.         <s:Transition fromState="normal" toState="closed" autoReverse="true">
  33.             <s:Fade duration="150" target="{chrome}"/>
  34.         </s:Transition>
  35.  
  36.         <s:Transition fromState="disabled" toState="disabledAndClosed" autoReverse="true">
  37.             <s:Fade duration="150" target="{chrome}"/>
  38.         </s:Transition>
  39.     </s:transitions>
  40.        
  41.     <!— Defines the background and content group used by this skin. –>
  42.     <s:Group id="chrome" left="0" right="0" top="0" bottom="0" visible.closedGroup="false">
  43.         <!—
  44.                 Defines the appearance of the SkinnablePopUpContainer class‘s background.
  45.                 In this case a FXG file is used to draw the background.
  46.                 –>
  47.                 <skins:BackGroundAlert id="background" left="0" right="0" top="0" bottom="0"/>
  48.        <!— @copy spark.components.SkinnableContainer#contentGroup –>
  49.        <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" minWidth="0" minHeight="0">
  50.            <s:layout>
  51.                <s:BasicLayout/>
  52.            </s:layout>
  53.        </s:Group>
  54.    </s:Group>
  55.    
  56. </s:Skin>

And this is the FXG used by the skin class to draw the background:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <Graphic version="2.0" xmlns="http://ns.adobe.com/fxg/2008"
  3.         xmlns:d="http://ns.adobe.com/fxg/2008/dt"
  4.         xmlns:flm="http://ns.adobe.com/flame/2008"
  5.         scaleGridLeft="10" scaleGridTop="10"
  6.         scaleGridRight="90" scaleGridBottom="90">
  7.       <Rect width="100" height="100" radiusX="10">
  8.         <fill>
  9.           <LinearGradient x="190.417" y="0" scaleX="361.667" rotation="90">
  10.             <GradientEntry ratio="0" color="#FFFFFF"/>
  11.             <GradientEntry ratio="0.0424137" color="#E1DBCE"/>
  12.             <GradientEntry ratio="0.0886452" color="#CEC3AE"/>
  13.             <GradientEntry ratio="0.139618" color="#C4B89F"/>
  14.             <GradientEntry ratio="0.208589" color="#C2B59B"/>
  15.             <GradientEntry ratio="0.588957" color="#C2B59B"/>
  16.             <GradientEntry ratio="0.758513" color="#C0B399"/>
  17.             <GradientEntry ratio="0.852955" color="#B2A58E"/>
  18.             <GradientEntry ratio="0.932468" color="#918372"/>
  19.             <GradientEntry ratio="1" color="#594A42"/>
  20.           </LinearGradient>
  21.         </fill>
  22.         <stroke>
  23.           <SolidColorStroke weight="3"/>
  24.         </stroke>
  25.       </Rect>
  26. </Graphic>

Download

You can download a working Flex project that includes all the code used in this article from here.

Comments

5 Responses to “Flex Mobile Development: Creating Dialog Windows”

  1. 1. Lionel on August 10th, 2011 9:56 pm

    Very useful. Thanks for posting that !

  2. 2. juan mendez on August 12th, 2011 2:37 am

    hi, i am reading your blog while i am preparing to show how to create a preference view in native android and mobile flex. :) thanks for the post

  3. 3. Juan Mendez on October 21st, 2011 4:31 am

    I wanted to finally share my dialog example using e-skimo :) http://blog.flexnroses.com/?p=126

  4. 4. Elijah Kamuyu on November 28th, 2011 3:41 pm

    Hi this Popup list works like a charm thank you, But I have noticed an error when you try to populate the array with only one record. Can you try it out and let me know

  5. 5. Emmanuel on January 30th, 2012 5:28 pm

    Why is SkinnablePopUpContainerSkin extending the mxml skin classes ? They say mxml skin with state are a performance killer for mobile…

    This popup is a bit sluggish on iPad1, I was forced to recreate the skin base on MobileSkin.

Leave a Reply




Switch to our mobile site