Jason Szeto (Dev)
Jacob Goldstein (QA)
dropDown component - general term referring to a component that contains an anchor button and a dropDown
popUp - refers to the DisplayObject displayed by the PopUpAnchor component
The PopUpAnchor component is used to display a popUp in the context of a layout. The PopUpAnchor component itself has no visual appearance, but it has dimensions and can participate in layout.
The PopUpAnchor displays the popUp by adding it to the PopUpManager, then sizes and positions the popUp relative to itself.
PopUpAnchor is useful for dropDown components, such as DropDownList or DropDownColorPicker. For DropDownList, PopUpAnchor is used to open and close the dropDown List. Since PopUpAnchor uses the PopUpManager to display its popUp, this ensures that the dropDown List appears above all other controls.
A video player requires a volume slider. The video player design calls for minimizing the space used by the interaction controls. The player has a small button with a volume icon. When the button is pressed, a VSlider slides down below the button. When a volume is selected on the slider, the VSlider slides back towards the button and is hidden.
The popUp
property is a UIComponent displayed by the PopUpManager. It is the default property and is often the only child tag of the PopUpAnchor tag. The popUp
can be a Group, container, or a single component. For example, in a DropDownList, the popUp
is a DataGroup which holds the item renderers.
The displayPopUp
property controls whether the popUp is displayed or not. If the value is true, then the popUp
is added to the PopUpManager and then sized and positioned. If the value is false, then the popUp
is removed from the PopUpManager.
The popUp
dimensions are determined in the following order:
Width:
autoSizePopUpWidth
is true, use the actual width of the PopUpAnchorpopUp's
explicitWidth if specifiedpopUp's
measuredWidthHeight:
autoSizePopUpHeight
is true, use the actual height of the PopUpAnchorpopUp's
explicitHeight if specifiedpopUp's
measuredHeightThe popUp
dimensions are not affected by the popUp
positioning.
The popUpPosition
property controls the position of the popUp
. Sizing and positioning are independent of each other. This property can have the following values:
The RelativePosition
class is an enum class that contains static properties for each of the above positions.
If the popUp is not entirely on the stage at its given position, the PopUpAnchor will reposition the popUp to keep it on the stage. For example, if a PopUpAnchor with popUpPosition = "right" is located on the right edge of the application, its popUp will appear to the left of the PopUpAnchor.
Since the popUp
is not a display list child of the PopUpAnchor, it doesn't automatically have all of the transforms (scale, rotation, skew) or alpha applied to it. Thus is it necessary to apply the PopUpAnchor's concatenated transform matrix (which contains the combined transforms applied to the PopUp and its ancestors) to the popUp
. The alpha property of the PopUpAnchor multiplied by the alpha properties of its ancestors is applied to the popUp's
alpha property.
The transforms and alpha are applied to the popUp
whenever it is displayed. If the PopUpAnchor transforms or alpha have changed while the popUp
is displayed, the transforms and alpha will be reapplied to the popUp
. If the PopUpAnchor ancestor's transforms or alphas are changed while the popUp
is displayed, they will not be reapplied to the popUp
. Instead, it will be up to the developer to call PopUpAnchor's updatePopUpTransform
function when the PopUpAnchor ancestor's transforms or alphas have changed.
It will be common to animate the popUp
when it is displayed and hidden. Effects can be run either upon the popUp
directly, or upon the PopUpAnchor. Since transform changes on the PopUpAnchor are applied to the popUp
, it is possible to animate the PopUpAnchor and have those effects affect the popUp
. For example, effects like Move, Fade, Resize and Zoom can be applied to the PopUpAnchor. Applying the effects to the PopUpAnchor allows the effect to respect some of the PopUpAnchor's layout constraints. Mask effects and Shader effects should be run on the popUp
since they require applying a mask to the target or taking a bitmap snapshot of the target.
If an effect modifies the ancestors of the PopUpAnchor, the effect can call updatePopUpTransform
to reapply the transforms to the popUp
while the effect is playing.
package spark.components
{
public class PopUpAnchor extends UIComponent
{
/**
* If true, the popUp's height is set to the value of the PopUpAnchor's height.
*
* @default false
*/
public function set autoSizePopUpHeight(value:Boolean):void;
public function get autoSizePopUpHeight():Boolean;
/**
* If true, the popUp's width is set to the value of the PopUpAnchor's width.
*
* @default false
*/
public function set autoSizePopUpWidth(value:Boolean):void;
public function get autoSizePopUpWidth():Boolean;
/**
* IUIComponent to add to the PopUpManager when the PopUpAnchor is opened.
* If the popUp implements IFocusManagerContainer, the popUp will have its
* own FocusManager so that, if the user uses the TAB key to navigate between
* controls, only the controls in the popUp will be accessed.
*/
public function set popUp(value:IUIComponent):void;
public function get popUp():IUIComponent;
/**
* Position of the popUp when it is opened.
* Possible values are "left", "right", "above", "below", "center", and "exact"
*
* @default "exact"
*/
public function set popUpPosition(value:String):void;
public function get popUpPosition():String;
/**
* If true, add the popUp to the PopUpManager. If false, remove it.
*
* @default false
*/
public function set displayPopUp(value:Boolean):void;
public function get displayPopUp():Boolean;
/**
* This function is called when the popUp is positioned when it is displayed
* or when updatePopUpTransform() is called. Override this function to
* alter the position of the popUp.
*/
protected function positionPopUp():void;
/**
* Call this function to update the popUp's transform matrix. Typically
* this would be called while performing an effect upon the PopUpAnchor.
*/
public function updatePopUpTransform():void;
}
}
package spark.core
{
public class RelativePosition
{
/**
* Positions the popUp to the left of the PopUpAnchor
*/
public static const LEFT:String = "left";
/**
* Positions the popUp to the right of the PopUpAnchor
*/
public static const RIGHT:String = "right";
/**
* Positions the popUp to above the PopUpAnchor
*/
public static const ABOVE:String = "above";
/**
* Positions the popUp to below the PopUpAnchor
*/
public static const BELOW:String = "below";
/**
* Positions the popUp in the center of the PopUpAnchor
*/
public static const CENTER:String = "center";
/**
* Positions the popUp at the exact position of the PopUpAnchor
*/
public static const EXACT:String = "exact";
}
}
The following example is a sample volume slider. When you roll over the anchor button, the slider appears on top of the anchor, centered both horizontally and vertically. When a volume is selected, the slider disappears. This example does not use any animation. Setting the horizontalCenter style on the PopUpAnchor allows the popUp to be centered horizontally relative to the anchor button.
<s:Group>
<s:Button label="v" width="30" rollOver="slide.displayPopUp = true"/>
<s:PopUpAnchor popUpPosition="center" horizontalCenter="0" top="0" bottom="0" width="18" id="slide">
<s:Group>
<s:Rect left="0" right="0" top="0" bottom="0">
<s:fill>
<s:SolidColor color="0xc9c9c9"/>
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x111111"/>
</s:stroke>
</s:Rect>
<s:VSlider top="4" right="4" left="4" bottom="4" maxHeight="40" valueCommit="slide.displayPopUp = false"/>
<s:filters>
<s:DropShadowFilter/>
</s:filters>
</s:Group>
</s:PopUpAnchor>
</s:Group>
\
The following example display a search box to the right of the "Search" LinkButton. When the button is clicked, the search box opens up to the right. When the "Find" button in the search box is clicked, then the search box is closed back up. Animation is used to show and hide the search box. The animation is playing directly on the PopUpAnchor's popUp.
<fx:Style>
.popUpBox
{
backgroundColor : #e9e9e9;
borderStyle : "solid";
paddingTop : 2;
paddingBottom : 2;
paddingLeft : 2;
paddingRight : 2;
}
</fx:Style>
<fx:Declarations>
<mx:Sequence id="hideSearch">
<s:Scale target="{searchPopUp.popUp}" scaleXFrom="1" scaleXTo=".1" duration="200"/>
<mx:SetPropertyAction target="{searchPopUp}" name="displayPopUp" value="false"/>
</mx:Sequence>
<mx:Sequence id="showSearch">
<mx:SetPropertyAction target="{searchPopUp}" name="displayPopUp" value="true"/>
<s:Scale target="{searchPopUp.popUp}" scaleXFrom=".1" scaleXTo="1" duration="200"/>
</mx:Sequence>
</fx:Declarations>
<s:Group>
<mx:LinkButton label="Search" click="showSearch.play() "/>
<s:PopUpAnchor id="searchPopUp" left="0" right="0" popUpPosition="right" styleName="popUpBox">
<mx:HBox horizontalScrollPolicy="off" verticalScrollPolicy="off">
<s:TextInput width="80" id="searchField"/>
<s:Button label="Find" click="hideSearch.play();"/>
</mx:HBox>
</s:PopUpAnchor>
</s:Group>
\
The following example uses states to control when the PopUpAnchor's popUp is displayed. It uses transitions to play animations between states. When the "Email" LinkButton is pressed, it fades in an email form below it. Clicking on "Send" or "Cancel" will hide the email form, fading it back out. By only including the PopUpAnchor in the "open" state, the form is only instantiated when it is displayed.
<fx:Style>
.popUpBox
{
backgroundColor : #e9e9e9;
borderStyle : "solid";
paddingTop : 2;
paddingBottom : 2;
paddingLeft : 2;
paddingRight : 2;
}
</fx:Style>
<s:states>
<s:State name="normal" />
<s:State name="emailOpen" />
</s:states>
<s:transitions>
<mx:Transition fromState="*" toState="*">
<mx:Sequence>
<s:Fade target="{emailPopUp.popUp}" duration="250"/>
</mx:Sequence>
</mx:Transition>
</s:transitions>
<s:Group x="60">
<mx:LinkButton label="Email" click="currentState = 'emailOpen'"/>
<s:PopUpAnchor id="emailPopUp" left="0" bottom="0" popUpPosition="below" styleName="popUpBox"
includeIn="emailOpen" displayPopUp.normal="false" displayPopUp.emailOpen="true">
<mx:Form>
<mx:FormItem label="From :">
<s:TextInput/>
</mx:FormItem>
<mx:FormItem label="To :">
<s:TextInput/>
</mx:FormItem>
<mx:FormItem label="Subject :">
<s:TextInput/>
</mx:FormItem>
<mx:FormItem label="Message :">
<s:TextArea width="100%" height="100" maxChars="120"/>
</mx:FormItem>
<mx:FormItem direction="horizontal">
<s:Button label="Send" click="currentState = 'normal'"/>
<s:Button label="Cancel" click="currentState = 'normal'" />
</mx:FormItem>
</mx:Form>
</s:PopUpAnchor>
</s:Group>
None
None
None
None
None
None
None
None
None
Should PopUpAnchor implement IVisualContainer? Scroller does. This seems like a similar case. Most of the implementation will throw RTEs.
The PopUpAnchor doesn't parent the popUp on its display list, so it doesn't really act as a container.
Should the PopUpAnchor support lazy creation of the popUp? Should the popUp only get instantiated when displayPopUp is true?
Should the PopUpAnchor apply changes to its transform properties (scale, rotation, translation, skew) and alpha property to the popUp
while it is displayed? Or should the developer be forced to call updatePopUpTransform
if these properties are modified while the popUp
is displayed? Playing an effect on the PopUp is a common way to modify the transform properties.
No, it should be sufficient to call updatePopUpTransform while an effect is playing
Should the PopUpAnchor dispatch open and close events? Setting the open property should immediately add the popUp to the displayList and make it visible, so I don't think events are necessary.
No, the popUp is opened immediately when the displayPopUp is set to true. If open and close animations delay the appearance of the popUp, it is up to the developer to listen for the effect end events.
What about naming PopUp -> PopUpAnchor and then renaming all of the contentX properties to popUpX? The PopUp component itself doesn't actually get popped up. People usually associate the term "popUp" with a visual window that is displayed above other controls. So it makes more sense to name the "content" as "popUp". The anchor is the area in the layout that determines the popUp's position and dimensions.
Renamed PopUp -> PopUpAnchor, and changed all contentX properties to popUpX properties.
Should the PopUp support the use case of providing a declarative way to add a popUp to the PopUpManager? In this use case, there is no anchor and thus no need to size and position the popUp relative to the anchor. The main purpose is to add a dialog box or floating window to the application. If we support this use case, then we would expose the modal flag and would just center the popUp in the application.
No, this is not a use case for an anchored popUp component.
How do we handle focus management for the popUp? Do we need something to implement the IFocusManagerContainer interface?
PopUpManager adds a FocusManager to a popUp that implements IFocusManagerContainer. Since the popUp
property can be any IUIComponent, it is up to the developer to decide if they want focus management within their popUp. It would be a good idea to add this information to the ASDocs
Documentation should include a lot of examples.