Building Flex 4 Containers with Multiple Content Areas

Back in the days of Flex 3, if you wanted multiple content areas in your main application, you’d need to arrange some set of containers (Canvas, HBox, VBox) in the app and fill them with content. It was just your basic Flex 3 development process. The danger, of course, is that you are mixing content with presentation, aka bad separation of concerns. Today, with the power of Flex 4 skins, we can avoid this issue by moving the presentation layer into a skin (or set of skins). And thus, we can do a much better job achieving a happy level of separation of concerns.

The Flex 3 Way

To give a concrete example, I’ll build a blog layout (yes, another blog layout) with a header, footer, sidebar, and main content areas. But before we get started, let’s review the old Flex 3 way:

The above code comes from a previous post, Designing in Flex 3, but has been modified to make sense here. You’ve got you basic blog design: a box for the header, footer, and body, where body is subsequently is divided into a main content area and a sidebar.

The 3-in-4 Way, aka The Wrong Way

The unfortunate next step in a Flex developer’s evolution is what I like to call the Flex 3-in-4 way. This is a the way of neanderthals, which is to say, it is an evolutionary dead end. If you ever have the bad luck to see 3-in-4 code, you can be sure you are dealing with a novice Flex 4 developer. In general, the 3-in-4 way consists of making the simple transcription: Canvas → Group, HBox → HGroup, VBox → VGroup. But the most damning tipoff of a 3-in-4 developer is the assertion that one is now a Flex 4 developer and the learning curve wasn’t all that bad. While I do think Flex 4 is more of an evolutionary release than a revolutionary release, it’s different enough. And it is particularly different on the design side of the framework, how it handles skins, layout, etc.

If we just transcribe the above example, we get some classic 3-in-4 code:

As you can see, the main app is now a nice set of semantic buckets, one for each of the content areas. Header stuff goes in the headerContent bucket, footer stuff goes in the footerContent bucket, etc.

Building a Multi Content Area Container

Second, we need to create a custom container with the nice set of semantic buckets used in the above code. This is achieved by following a straightforward formula:

Add Buckets – add some content buckets (in the form of xxxContent) as Arrays. These become the MXML tags used to bucket components together. Each content bucket has a public getter, but most importantly a public setter that accepts an incoming Array of IVisualElements and uses the magical mxmlContent property to assign it to the associated SkinPart.

Add SkinParts – add some matching SkinParts (in the form of xxxGroup) as spark Groups. There are used in the custom skin to display the content. Also, I usually set required="false" to make everything optional.

The custom component code is actually easier to follow then the description. Here is a custom container with only one additional content bucket, sidebarContent, and its matching SkinPart, sidebarGroup:

Following the four steps: we extend Application, have a sidebarContent bucket and its associated sidebarGroupSkinPart, and override partAdded() and partRemoved() to wire everything together.

Skinning a Multi Content Area Container

Skinning in Flex 4 is awesome, and like everyone says, it’s easily one of the best new features in the framework. While I find the skinning process fairly straightforward, I would never call it trivial, mostly due to the depth and flexibility of the skinning system.

We need a custom skin for our custom multi content area component. This is probably the 10% case for skinning, but it’s also the coolest. In my experience, an average Flex 4 app has many Button skins (like 10 or even 20), a few default component skins (skins for List, DropDownList, TextInput, etc.), and maybe only two or three skins for custom components.

The skin itself is nothing special. To display our custom component’s SkinParts, we simply include a Group with the matching id attribute. For example, our skin will include a <s:Group id="sidebarGroup" /> to display the sidebarGroupSkinPart. Just rinse, wash, repeat, to add all of our custom content areas in the container to the skin.

In this trivial skin, we just shove all the content groups (including SkinnableContainer‘s default Group, contentGroup) into a VGroup. Also note, we correctly set HostComponent to our custom container. If you are thinking, "Hey, this skin looks similar to the Flex 3 and 3-in-4 example code, just minus the content" that’s exactly the point.

Using skinClass to wire a skin to a component is so 2009. The sample app has its CSS inline, but in any real app I’ll always put this in an external file.

Conclusion

After this, there’s really not much more to say. You can certainly create a more complicated arrangement of the multiple content areas by making a more complicated skin. I’ve done exactly this in the final sample, which includes three different skins and a skin switcher (click 1, 2, or 3 to switch skins).

Files

Comments

I’m not sure you need to call invalidateSkinState() in the sidebarContent setter. The reason it’s done like this in Panel‘s controlBarContent property is because the skin state of the component changes when control bar content is present (for instance from “normal” to “normalWithControlBar”). However, here since the skin state isn’t changing, I don’t think you need it.

-Ryan

Scottae

7.15.2010

2

Very nice article. It is an eye opener for me since I am familiar with Flex 3 and new to using Flex 4. Thanks.

@Ryan: Good catch, totally my bad. I updated the post to remove the superfluous invalidateSkinState() from the custom container code.

daniel

7.16.2010

4

Nice presentation. These are the exact same issues I struggled with when attempting to write a custom component for the face of a simple application. Reading the source code and skin file for the spark Panel container and struggling to understand what was going on took me a day or two but was an important step. I like how you make a point to call out the wrong way of doing things.

Q: in looking at the code, it’s not clear how the “contentGroup” is getting mapped to the skin since there’s no id on the RichTextArea tag in MultiContentArea.mxml and no mention of “contentGroup” in MainApp.as. Am I missing something simple?

@Daniel: Ah the “magic” contentGroup. This is the “default” content bucket in SkinnableContainer. So anything that goes inside the open and close tag of a container is put into this group automatically.

For example, <s:Application> ...stuff... </s:Application>, all of the stuff goes into the default content bucket, and SkinnableContainer pushes it to the skin with a SkinPart called contentGroup.

So, if you create an Application skin or a Panel skin, there is an <s:Group id="contentGroup" /> that you need to display and position.

I would just add that if you don’t see the need for skins, SkinnableContainer, custom containers, and friends, keep writing Flex 3. I’d just set my default SDK to Flex 3.5 in Flash Builder and not worry about it.

We are using the exactly the same approach to display multiple content area in our Flex 4 based application. The only difference is that our custom content areas are typed of IDeferredInstance type in order to support “progressive” loading of
separate content areas.

BTW, in Flex 3 we had an ability to create so-called “templated” components

@Jabby: Great point about using IDeferredInstance, and a really great point about using “templated” components for the Flex 3 holdouts.

Ron

8.25.2010

16

In your example of “how to do it the flex 4 way” you don’t even seperate concerns properly yourself so imho you shouldn’t be the one talking with such a condescending tone as if you are the king of flex 4, because from what I see here you certainly are not.

I really like what you’ve done here. The separation is really nice, however I think there is a fundamental problem caused by the way Flex is put together. In your examples, layout is governed in your content-slots by the groups layout props inside the skins. This is great, because layout declarations are kept inside the skin, and you can declare the content inside your main mxml file without needing to polute the semantic tags with any layout code. However, what if the layout is a basic layout and you need a button at x=”30″ / y=”45″ and an image with width=”100″ height=”200″? You are stuck declaring this layout information inside the main mxml file.

If you look at the way HTML handles this, complete separation is achieved through CSS. We can almost get there, but x/y and width/height are not settable through CSS, so we are stuck.

We can work around this limitation by using another layer – a view that fits into the content slot and declares its content as skin parts, but this is a far from ideal solution.

The problem with BasicLayout is that it forces layout information into the component tags. As you say, layouts are great, but it seems like this nice separation breaks down if you need to position items individually.

I wonder if anyone has looked at creating custom layouts for non-repeating content? Every single example I’ve seen has assumed repetion. It seems to me, we should be able to create a view-specific layout that can position items individually – so that the decision about where to position them is contained in the layout, not in the MXML markup. That way we could maintain semantic declartions right down to the contents of the containers.

@Neil: I really just followed what the Adobe engineers did when they build the spark Panel component. Since they used mxmlContent, I used mxmlContent. As far as I know, it’s not possible any other way.

Sachin Chandorkar

4.17.2012

24

Excellent article. Thanks for the explanation

Stg

8.19.2012

25

Hi! I followed your example and it works really well, till point where I try to bind some properties of elements in for ex. footer to properties in header. bindings simply not working…:( Can you tell, what can be a problem