Spark Vertical & Horizontal Layout - Functional and Design SpecificationSpark Vertical & Horizontal Layout - Functional and Design Specification | Summary and Background | Usage Scenarios | Detailed Description | API Description | Examples and Usage | B features | Additional Implementation Details | Prototype Work | Compiler Work | Web Tier Compiler Impact | Flex Feature Dependencies | Backwards Compatibility | Accessibility | Performance | Globalization | Localization | Issues and Recommendations | Documentation | QA
Summary and BackgroundIn the Spark architecture, the containers and the layouts are separate objects. With Spark, we are providing generic containers, custom layouts as well as a few stock layouts with functionality that is parallel to the most-commonly used Halo layout containers. This spec describes the HorizontalLayout and VerticalLayout, which are the Spark counterparts of the Box layout. Goals:
Non-goals:
Covered separately:
Usage Scenarios
Detailed DescriptionBoth HorizontalLayout and VerticalLayout extend LayoutBase. HorizontalLayout is the default layout for HGroup, and VerticalLayout is the default layout for VGroup and List. The HorizontalLayout arranges the container's elements in left-to-right order. The VerticalLayout arranges the container's elements in top-to-bottom order. Both layouts respect the value of the element's includeInLayout property. Both layouts support gaps between the elements and padding area between the container borders and the elements. HorizontalLayout properties
VerticalLayout properties
HorizontalLayout/VerticalLayout public methods
Calculating the Default Size - measure()The HorizontalLayout's major direction/axis is horizontal. The VerticalLayout's major direction / axis is vertical.
To calculate the measured minimum size, both layouts follow the same steps as for the measured size, with the only difference that if the element's size is constrained to the container size, then the layouts take into account the element's minimum size instead of the element's preferred size. For 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/halo"
width="500" height="500">
<s:Group id="g">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Button width="50" minWidth="25"/>
<s:Button width="100%" minWidth="30"/>
</s:Group>
</s:Application>
when the Group "g" calculates the measured width, it will be the maximum of the first button's preferred width (50) and second button's preferred width (70, which is the default button size) yielding the total measured with as 70. Size and Arrange Elements - updateDisplayList(width, height)Both VerticalLayout, HorizontalLayout size and position the elements very similarly. Some calculations are based on the content width / height of the container (along the minor axis). In these cases the layouts calculate in advance the content width / height as the maximum of element's size, where element's size is:
The size of the elements along the major axis is calculated according to the following order of precedence:
The size of the elements along the minor axis is calculate according to the following order of precedence:
Distribution of percent size along the major axis - when there are several elements with percent size along the major axis - for example three elements with percentHeight in a VerticalLayout - then the layout calculates the actual sizes as normalized percentages of the available space according to the following steps:
Positioning the elements - the layouts determine the major axis position (y coordinate for the VerticalLayout) by arranging the elements top-to-bottom (VerticalLayout) or left-to-right (HorizontalLayout), taking into account the gap setting as well as the size of the elements as determined by the steps outlined above. The position along the minor axis (x coordinate for the VerticalLayout) is determined according to the alignment property (horizontalAlign for the VerticalLayout):
Finally, the content size is defined as:
Scrolling supportVerticalLayout / HorizontalLayout inherit the scrolling along the minor axis from LayoutBase. The scrolling along the major axis work on per-element basis regarding the scrollRect:
In all cases while scrolling, the scrollRect is moved no more than its width/height. For example if there's a very large item that is way taller than the scrollRect and its bottom edge is visible, it will take multiple ScrollUnit.PAGE_UP scrolls to reach the top edge of the element (in a VerticalLayout). Refer to the LayoutBase spec for details on the scrolling APIs. NavigationVerticalLayout / HorizontalLayout implement the LayoutBase method getDestinationIndex(). The behavior for VerticalLayout is:
The behavior for the HrozontalLayout is similar, with the exception that page left/right is treated the same as page up/down and left/right and up/down are swapped. Also page left/right/up/down are implemented in terms of viewport width. Pixel Boundaries and RoundingThe VerticalLayout and HorizontalLayout take care to perform rounding for any computation that may yield fractional numbers, assuming that the inputs are always integer numbers:
API Description
package spark.layout
{
public class HorizontalLayout extends LayoutBase
{
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// gap
//----------------------------------
/**
* The horizontal space between layout elements.
*
* Note that the gap is only applied between layout elements, so if there's
* just one element, the gap has no effect on the layout.
*
* @default 6
*/
public function get gap():int
public function set gap(value:int):void
//----------------------------------
// columnCount
//----------------------------------
[Bindable("propertyChange")]
/**
* Returns the current number of elements in view.
*
* @default -1
*/
public function get columnCount():int
/**
* @private
*
* Sets the <code>columnCount</code> property and dispatches
* a PropertyChangeEvent.
*/
private function setColumnCount(value:int):void
//----------------------------------
// paddingLeft
//----------------------------------
/**
* Number of pixels between the container's left border
* and the left edge of the first layout element.
*
* @default 0
*/
public function get paddingLeft():Number
public function set paddingLeft(value:Number):void
//----------------------------------
// paddingRight
//----------------------------------
/**
* Number of pixels between the container's right border
* and the right edge of the last layout element.
*
* @default 0
*/
public function get paddingRight():Number
public function set paddingRight(value:Number):void
//----------------------------------
// paddingTop
//----------------------------------
/**
* All layout elements will have at least this much space
* above them.
*
* @default 0
*/
public function get paddingTop():Number
public function set paddingTop(value:Number):void
//----------------------------------
// paddingBottom
//----------------------------------
/**
* All layout elements will have at least this much space
* below them.
*
* @default 0
*/
public function get paddingBottom():Number
public function set paddingBottom(value:Number):void
//----------------------------------
// requestedColumnCount
//----------------------------------
/**
* The measured size of this layout will be big enough to display
* the first <code>requestedColumnCount</code> layout elements.
*
* If <code>requestedColumnCount</code> is -1, then the measured
* size will be big enough for all of the layout elements.
*
* This property implies the layout target's <code>measuredWidth</code>.
*
* If the actual size of the <code>target</code> has been explicitly set,
* then this property has no effect.
*
* @default -1
*/
public function get requestedColumnCount():int
public function set requestedColumnCount(value:int):void
//----------------------------------
// columnWidth
//----------------------------------
/**
* If variableColumnWidth="false" then
* this property specifies the actual width of each layout element.
*
* If variableColumnWidth="true" (the default), then this property
* has no effect.
*
* The default value of this property is the preferred width
* of the typicalLayoutElement.
*/
public function get columnWidth():Number
public function set columnWidth(value:Number):void
//----------------------------------
// variableColumnWidth
//----------------------------------
/**
* Specifies that layout elements are to be allocated their
* preferred width.
*
* Setting this property to false specifies fixed width columns.
*
* If false, the actual width of each layout element will be
* the value value of <code>columnWidth</code>.
*
* Setting this property to false causes the layout to ignore
* layout elements' percentWidth.
*
* @default true
*/
public function get variableColumnWidth():Boolean
public function set variableColumnWidth(value:Boolean):void
//----------------------------------
// firstIndexInView
//----------------------------------
[Bindable("indexInViewChanged")]
/**
* The index of the first column that's part of the layout and within
* the layout target's scrollRect, or -1 if nothing has been displayed yet.
*
* Note that the column may only be partially in view.
*
* @see lastIndexInView
* @see fractionOfElementInView
*/
public function get firstIndexInView():int
//----------------------------------
// lastIndexInView
//----------------------------------
[Bindable("indexInViewChanged")]
/**
* The index of the last column that's part of the layout and within
* the layout target's scrollRect, or -1 if nothing has been displayed yet.
*
* Note that the column may only be partially in view.
*
* @see firstIndexInView
* @see fractionOfElementInView
*/
public function get lastIndexInView():int
//----------------------------------
// verticalAlign
//----------------------------------
[Inspectable(category="General", enumeration="top,bottom,middle,
justify,contentJustify", defaultValue="top")]
/**
* Vertical alignment of layout elements.
*
* If the value is one of "bottom", "middle", "top" then the
* layout element is aligned relative to the target's contentHeight.
*
* If the value is "contentJustify" then the layout element's actual
* height is set to the contentHeight.
*
* If the value is "justify" then the layout element's actual height
* is set to the target's height.
*
* This property does not affect the layout's measured size.
*
* @default "top"
*/
public function get verticalAlign():String
public function set verticalAlign(value:String):void
/**
* An index is "in view" if the corresponding non-null layout element is
* within the horizontal limits of the layout target's scrollRect
* and included in the layout.
*
* Returns 1.0 if the specified index is completely in view, 0.0 if
* it's not, and a value in between if the index is partially
* within the view.
*
* If the specified index is partially within the view, the
* returned value is the percentage of the corresponding
* layout element that's visible.
*
* Returns 0.0 if the specified index is invalid or if it corresponds to
* null element, or a ILayoutElement for which includeInLayout is false.
*
* @return the percentage of the specified element that's in view.
* @see firstIndexInView
* @see lastIndexInView
*/
public function fractionOfElementInView(index:int):Number
}
}
Examples and UsageExample from the Spark VideoPlayer skin: <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<!-- host component -->
<fx:Metadata>
[HostComponent("spark.components.VideoPlayer")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="buffering" />
<s:State name="connectionError" />
<s:State name="disabled" />
<s:State name="disconnected" />
<s:State name="loading" />
<s:State name="paused" />
<s:State name="playing" />
<s:State name="seeking" />
<s:State name="stopped" />
</s:states>
<s:layout>
<s:VerticalLayout horizontalAlign="center"/>
</s:layout>
<s:VideoElement id="videoElement" />
<s:HSlider id="scrubBar" />
<s:Group>
<s:layout>
<s:HorizontalLayout />
</s:layout>
<s:Button id="stopButton" label="Stop" />
<s:ToggleButton id="playPauseButton" skinClass="spark.skins.default.VideoPlayerPlayPauseButtonSkin" label="Play" />
<s:ToggleButton id="muteButton"
skinClass="spark.skins.default.VideoPlayerMuteButtonSkin"
label="Mute" />
<s:VSlider id="volumeBar" liveDragging="true" height="21"
valueInterval=".1" />
<s:Button id="fullScreenButton" label="Fullscreen" />
</s:Group>
</s:SparkSkin>
Example from the Spark List skin: <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
minWidth="112" minHeight="112"
alpha.disabled="0.5">
<fx:Metadata>
[HostComponent("spark.components.List")]
</fx:Metadata>
......
<s:Scroller left="1" top="1" right="1" bottom="1" id="scroller">
<s:DataGroup id="dataGroup"
itemRenderer="spark.skins.default.DefaultItemRenderer">
<s:layout>
<s:VerticalLayout gap="0" horizontalAlign="contentJustify" />
</s:layout>
</s:DataGroup>
</s:Scroller>
</s:SparkSkin>
B featuresHorizontalLayoutTwo new properties:
VerticalLayoutTwo new properties:
Additional Implementation DetailsPrototype WorkBoth HorizontalLayout and VerticalLayout exist and are in almost complete state in the trunk. Compiler WorkNo. Web Tier Compiler ImpactNo. Flex Feature DependenciesDependencies on other Flex features. Backwards CompatibilityNo. AccessibilityDescribe any accessibility considerations. PerformanceGlobalizationNo issues. LocalizationCompiler FeaturesNo command-line params, warnings, errors, etc. Framework FeaturesNo RTE messages. No UI text, images, skins, sounds. Issues and RecommendationsDocumentationDescribe any documentation issues or any tips for the doc team. QAIf there are testing tips for QA, note them here, include a link to the test plan document. |
|
| You must be logged in to comment. |
|---|
How do I vertically align a VGroup? How do I horizontally align an HGroup? These layout options used to be available in the halo equivalents: HBox had horizontalAlign, VBox had verticalAlign.
Now VGroup only has horizontalAlign and HGroup only has verticalAlign.
I can write twice as much code and wrap an HGroup with a VGroup - or vice versa - but this seems like such a terrible solution that I hope its not the officially supported solution for all the "improvements" made in for spark.
I am in the same boat as Matthew. An intensive search on the internets does little to answer this question.
Is there currently a standard way of aligning elements vertically and horizontally using only one parent container?
I agree with Matthew. Please bring back the verticalAlign property to VGroup and horizontalAlign property to HGroup.
I can't think of any logical reason to remove this properties in the first place...
I also agree with the posters above. I haven't been using Flex very long and I'm sad to say that I can do a nice layout in Java much faster than I can in Flex 4 (you can take that as an insult if you like). I realize the layout / skinning system in Flex 4 can be very powerful, but I don't want to spend my time writing custom layout code (ever).
I've read articles on improving UI performance and a lot of them say to avoid nesting containers. Now I have to nest a ton of containers just to get some basic layouts set up so things look half decent. What gives?
Actually, major axis alignment (verticalAlign on VGroup/VerticalLayout and horizontalAlign on HGroup/HorizontalLayout) was recently added. See http://bugs.adobe.com/jira/browse/SDK-24416 for details. The spec hasn't been updated yet.

Apologies if this is not the correct place.
There is no mention here of the effect that switching from a state that is BasicLayout to a state that is Vertical/Horizontal layout .
It would appear that the x , y properties
are lost meaning that returning to the State that is BasicLayout the 'layout' is lost .
see http://bugs.adobe.com/jira/browse/SDK-21302 fmi.