Flash Layout Engine in Reflex

As a component platform Reflex is built on a foundation of core libraries and utilities. Because of the unique culture of the project most of these solutions are independently useful to the Flash developer. Its layout engine is one of Reflex’s profitable solutions and can structure the visual flow of any member of ActionScript’s display list.

The following demo illustrates one of the default layout algorithms in Reflex, named Dock (notice the minimal use of containers used to achieve the structure). Click and drag to resize:

Layout Laid Out

Maybe one of the first things you noticed while playing with the demo is that container’s just can’t get smaller than their children. This and other more subtle behaviors make up the physics of layout, the rules that Reflex embodies and simplifies in just 3 core classes: ILayout, ILayoutAlgorithm and the RenderEvent.


ILayout

A Layout object wraps any DisplayObject in Flash and provides most of the properties for a given layout system, such as minimum and maximum widths and heights. The demo above is made up of Flash-designed MovieClips and Sprites, no special base container class, creating Block layout’s that point to each. Block extends Layout and is the default layout system for components, providing various width/height features, margins, padding and other common properties for dividing the screen into rectangular sections. Other ILayout implementations may be created to easily support different layout systems, such as 3D.


ILayoutAlgorithm

One of the most important members of any Layout object is the algorithm. With each layout system comes a variety of supporting layout algorithms, defining the rules by which a specific container lays out its children. Through the Block-based layout system, the example above takes advantage of the specific algorithm Dock. This algorithm aligns children of a container to the LEFT, TOP, RIGHT, BOTTOM or FILL based on their dock and tile properties and allows a mixed layout within a single container. Other algorithms position and size children DisplayObject’s uniformly, such as in a stack or a row.


RenderEvent

Normally laying out a screen can be complicated because children affect the size of their container and containers determine the position and size their children. The driving force in Reflex’s layout engine is, by itself, a stand alone utility ideal for managing the “layout cycle”. RenderEvent isn’t very complicated but it simplifies the layout process and greatly increases performance. This is made possible in 3 ways:

  1. delaying layout computation to just before each screen redraw consolidates all of the property changes that affect both children and container
  2. dividing layout into two phases, where the measure phase allows a container to calculate its minimum (and maximum) size based on its contents, and the layout phase runs the algorithm that finally place those contents
  3. allowing each phase to run in order from the lowest to the highest depth in the display list ancestry (in the case of measure) or from the highest to the lowest depth (in the case of layout). For example, Flash’s stage and root would measure last, and layout first, then the children of root will layout, then their first-level children and so on. The reason for this feature is a little more involved but it makes a huge difference in performance


Contribution

Fortunately it’s very easy to customize display list layout by creating new layout algorithms. There are only two methods required, the measure() and the layout() methods, and these are automatically invoked precisely when they need to be. Robert Taylor got involved in the code and within an afternoon had built several of his own layout algorithms, complete with custom behaviors and tweening. Reflex as a platform offers a variety of components and solutions, but if layout is where your interests lie you can contribute without using or understanding anything else in the framework. Perhaps the best part is, because it works with any kind of DisplayObject, Reflex’s layout engine can be used in Flex, Flash or most any other ActionScript 3 environment. It’s universal!

19 Comments

  1. Posted on February 16, 2010 at 4:28 pm by felix

    Sounds great! Is the code available?

  2. Posted on February 16, 2010 at 5:09 pm by xtyler

    Demo-code added to the right-click menu of the example, and is dependent on the Reflex library at http://github.com/xtyler/reflex

  3. Posted on February 17, 2010 at 1:03 am by julien

    very nice stuff! thanks for sharing

  4. Posted on February 17, 2010 at 1:43 am by M.Althoff

    Universal? Just had a sneak peak into code and found alot of bindings and other compiler directives used. Isn’t that only possible with the Flex Framework ? Does this project compares with Java LayoutManagers? Great work anyways, looks promising…

  5. Posted on February 17, 2010 at 3:00 am by am

    Nice work!
    Could you provide a simple example in Flash IDE?

  6. Posted on February 17, 2010 at 3:32 am by Tomasz Maciag

    I’ve got it working with flash CS3. I’ve extracted PropertyChangeEvent and PropertyChangeEventKind from flight-framework source at code.google. I’ve cleared initial errors by changing ILayout implementation in Layout to match interface (replacing public variables with setters). BoxGraphic is not included in view source so i created movieclip with rectangle inside and set linkage to BoxGraphic.

  7. Posted on February 17, 2010 at 5:45 am by Fernando de França

    Awesome! Soon I’ll check it’s details.

  8. Posted on February 17, 2010 at 7:43 am by xtyler

    M. – [Bindable] properties are used as a shortcut during current development but will have to be replaced with getter/setters to support the Flash IDE. Reflex uses the Flight Framework binding solutions.

    Tomasz – that’s awesome! You really got your hands dirty, keep up the good work.

    The Reflex team is in the midst of rapid development to prepare for upcoming conferences and demonstrations, so we’re neglecting select features at times, such as full Flash Professional support. We’ll get back to it soon.

  9. Posted on February 17, 2010 at 8:29 am by James Ward

    Wow! That demo loaded so fast that I initially thought it was a screenshot of the demo! Nice work!

  10. Posted on February 26, 2010 at 4:11 pm by Sylvain Lecoy

    Did you notice that with Flex Builder 4 when we Eporting Release Build (optimized SWF or Adobe AIR File) the demo doesn’t work anymore ?

  11. Posted on March 3, 2010 at 8:16 am by Jonas Nyström

    Aargh, would really love to change some snowy northern swedish days to sunny and relaxed californian ones..! Good luck with your 360 Flex presentation! Looking forward to follow (and maybe somehow contribute) to the Reflex progress!

  12. Posted on March 28, 2010 at 6:30 am by Glidias

    I’ve peeked into the code and with the exception of ScrollBlock in the reflex.layout package, the rest of the layout classes do not require any Binding dependencies whatsoever, which makes this quite easy to extract out and integrate into a reusable BlockBehaviour class that can be applied to any display object (or IBoxModel-based) display for my own collection . After all, I need some basic dock and center fill liquid layout functionality, and this package, though it seems not fully incomplete in some parts (a bit of to-dos), can help in that area.

  13. Posted on March 29, 2010 at 5:31 am by xtyler

    I’m glad you were able to get in and use this! My friend Rob Taylor has already developed a suite of layout algorithms for his own project and doesn’t use anything else from the framework successfully. It’s a good test of the separation in Reflex.

    The Block class is already a reusable piece that will target any DisplayObject, you won’t need to do any extra work to create a “BlockBehavior”. Behaviors are specifically interactive elements for components, while Layouts, Skins etc are other types of reusable systems.

  14. Posted on April 1, 2010 at 9:39 am by Glidias

    I know Blocks can be used standalone. BlockBehaviour was just a standalone adaptor wrapper because my API uses a specific interface-method activate(target:*):void & destroy():void over a target object, which is pretty archaic/boiler-plate heavy on hindsight (What was i thinking?). I’d definitely have to refactor that to using a pure “target” setter as the standard (where setting target to ‘null disposes off the block/behaviour’s listeners), and therefore eliminate the interface dependencies and allow for cross-platform ease. In fact, the benefit of not using interfaces at all to set targets for behaviours is even better because some behaviour targets may not necessarily be InteractiveObjects. Without an interface, the coder is free to create ANY class with set target(val:MyOwnRequiredType), without resorting to casting. It’s simply assumed there’s a ‘target’ setter for such classes..

    It would be cool to allow Blocks the option to also bind their width and height properties to other properties of the target component, if required (since not all DisplayObjects’ width/height values reflect the measured width/height settings used for layouts).

  15. Posted on April 12, 2010 at 3:13 am by Scott

    Sorry if this is obvious but where is the reflex.swc?

  16. Posted on April 20, 2010 at 8:48 am by xtyler

    Scott, the Reflex initial website has finally been released and should have some additional information there. http://www.reflex.io

  17. Posted on April 23, 2010 at 4:02 am by Francis Varga

    Awesom framework! :)

    Do you have a FLA wherea all components are inluded? :)

    That’s very nice also, save many times :)…

  18. Posted on June 24, 2010 at 2:07 am by Scott

    The BoxGraphic isn’t included in the demo folder by the looks of things.

    Cheers,

    Scott

  19. Posted on February 13, 2012 at 3:11 pm by Triynko

    It’s interesting that I independently created a virtually identical layout framework in AS3 over 3 years ago for a grant-funded project, which is now used by over 6000 students across the state. Interesting… because I hate patents, precisely because technological development is so constrained that this kind of thing happens all the time, and people who think they’re oh-so-creative are just following a very intrinsic design process. Anyway…

    This all comes about given the constraints of the technology: minimizing layout calculations, supporting layout of any existing sprite, having different docking options (i.e. different “algorithms”, although this usually involves only 4 lines of code to compute the x,y,width,and height of a docked object from the remaining docking space), etc. For example, the code for “Left” dock is:

    c.width = ((dock_rect.width – dro – dm.width) * dr + dro) * sx; //takes into account leftover docking space, dock ratio offset (dro), horizonal (left+right) dock margins (dm.width), dock ratio, and x-scale
    cw = c.width / sx; //obtain actual width from control (accounts for min/max size restrictions)
    c.x = int(dock_rect.left + dm.left); //enforce integer precision for pixel-perfect positioning
    c.y = int(dock_rect.top + dm.top);
    c.height = (dock_rect.height – dm.height) * sy; //height remains floating point for more precise calculation of leftover-space
    dock_rect.left += (cw + dm.width); //shrink remaining space by moving it’s left edge

    I actually use my “Layout” base class (GUIControl) as the base class for most of my custom component, rather than wrapping everything by default, because it’s more efficient. For cases where wrapping is the only option, for example if I need to dock a standard TextField, then I have the GUIControlWrapper class for that.

    Docking options in my framework are numerous. Not only does it support: None, Left, Right, Top, Bottom, and Fill, but also built in are “anchor” options such as TopLeft, TopCenter, TopRight, etc. that hit all 8 such corners and midpoints, as well as a 9th, MiddleCenter. There are then the “anchor fill” varieties, that will anchor vertically or horizontally across the top, middle, bottom, sides, and center, for an additional 6 options. The anchoring modes are special in that they do not subtract from the “leftover space” or “dock rectangle”, so you could anchor something in the corner allowing it to float over the rest of your docked content without it interfering with their positioning.

    Next, there are DockMargins, DockRatio, and DockRatioOffset properties, which allow you to leave some space around your object, or dock something in the top 25% of an area (minus some offset), such that it will automatically expand to 25% of the parent container size (minus some optional fixed offset). Another example is that I can anchor a 25px close button onto a window, and give it a negative 25px top margin so it appears to rest on top of the window.

    The main docking modes support “loop around” with the leftover space, so that it resets once exhausted, so you can dock and dock and dock things that fill the space and create layers if you want.

    It also supports:
    *rotation, and automatically calculates and orthogonal bounding box for rotated controls for docking purposes
    *minimum and maximum width, height, and size
    *calculation of the content rectangle, including children, and optionally including stroke widths
    *ordering controls: to front, to back, forward, backward, to a specific depth
    *remove children of a particular type
    *clip contents to width/height of control to prevent overhang
    *layout suspend/resume to avoid unnecessary layout calculations, which is important, because this framework intentionally was designed to not delay layout operations to a later stage like your framework and the Flex framework do, because this framework wants changes in size/position to reflected universally and immediately upon being set to ensure interactive controllers have accurate information
    *shortcut method for wrapping standard controls: “wrapAndDockControl( control:DisplayObject, dock_width, dock_height, dock_style, dock_margins, wrapper_dock_style, wrapper_wrap_style, match_control_size:Boolean ), which allows you to wrap a control, set it’s size, stretch it to the wrapper size or leave it’s original size fixed, at the left edge, middle center, etc.

    GUIControl also overrides the default width and height properties of the display object, so that GUIControl objects can have definite sizes, independent of their content, which is not possible with the standard Sprite class, whose size could depend on the stroke widths of the graphics, causing imprecision and overflow. It also stores the original size of the graphical contents upon construction, and allows for setting a scale on these components independent of their original width/height, which again is not possible with the standard Sprite, whose width/height/scale are all tied together. Since all the docking “algorithms” take the control’s, size, margins, dock ratio, dock ratio offset, and scale into account, I can actually dock the same object of a single size at many different scales. It’s all very precise, accurate, and fast. 22 different standard docking options, plus support for a custom controller. The controllers also have access to the “resize” and “layout complete” events that the GUIControls fire, in order to achieve reflexive interactivity.

    Nice job on the clean 3-class framework. I’ll be looking into it, and seeing if I can learn anything or incorporate any ideas to improve my own. This is how technology advances, sharing ideas, not through hindering them with copyrights and patents :P

LEAVE A COMMENT