Earlier this week I started work on a new NookColor app (already done and submitted). One of the minor design elements I wanted was a simple background using a graphic. I had assumed this would be a simple matter. It's already easy to set a background color. However this turned out to be slightly more complex than I imagined. What follows is an example of how it can be done. Credit for this goes to Jason San Jose and Holly Schinsky. Please note that part of this blog entry is my understanding of what's going on and there is a strong possibility I could be wrong. Any mistakes - blame me. If it's perfect - thank them. ;)
Let's start off with a super simple Flex Mobile application. I've got a view based application with one view. Here's the top level Application.
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" firstView="views.BGTestHomeView">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:ViewNavigatorApplication>
And here is my view:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup horizontalAlign="center" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" width="100%" height="100%" verticalAlign="middle">
<s:Label text="Mobile Apps Rule!" width="75%" fontSize="50" textAlign="center" />
</s:VGroup>
</s:View>
Which produces the lovely...
Now - if I want to add a background color, I can do so in two places - either the root app (ViewNavigatorApplication) or the view. Putting it in the root will only work for a brief second. You can see the background color for a second right before the view loads. So let's just put it in the view.
<s:VGroup horizontalAlign="center" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" width="100%" height="100%" verticalAlign="middle">
<s:Label text="Mobile Apps Rule!" width="75%" fontSize="50" color="white" textAlign="center" />
</s:VGroup> </s:View>
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView" backgroundColor="blue">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
Note the addition of "blue" to the View as well as the white color for the label. This creates this awesomely pretty view:
Ok. So when I first discovered this, I assumed that there was probably some other argument, like backgroundImage or some such, that would just as easy. Unfortunately that's not the case. Some Googling turned up a few blog posts talking about how to do it for Flex 4 apps in general. The recommendation was to create a skin for the application as a whole. You can do this in pure ActionScript or MXML. Here's my attempt with MXML.
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" firstView="views.BGTestHomeView" skinClass="skins.myAppSkin">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:ViewNavigatorApplication>
Note the change here - I've added skinClass. Let's look at that file.
<fx:Metadata>
<![CDATA[
[HostComponent("BGTest")]
]]>
</fx:Metadata> <s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states> <s:BitmapImage width="100%" height="100%" source="@Embed('/images/grass.jpg')"/> <s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0" /> <s:ViewNavigator id="navigator" width="100%" height="100%" /> </s:Skin>
<?xml version="1.0" encoding="utf-8"?>
<s:Skin name="CustomApplicationSkin"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
>
At first I kind of thought of the skin file like a CSS sheet, where I'd specify just what I wanted to change. But - it's more like a "skeleton" or outline for your entire application. Notice I included the viewNavigator in there. And my content group. This is - from what I understand - the default way the mobile application would be laid out anyway. So my modification then was to simply include the image. End of story, right? Not exactly.
Turns out this "works", but the View ends up covering the background picture. This is where Jason's tip came in. If we go into our view and set the alpha of the background like so:
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView" backgroundAlpha="0">
We allow the content to show the background behind it. Here's the complete view. I added a black background to the label as well.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView" backgroundAlpha="0">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup horizontalAlign="center" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" width="100%" height="100%" verticalAlign="middle">
<s:Label text="Mobile Apps Rule!" width="75%" fontSize="50" color="white" textAlign="center" backgroundColor="black" />
</s:VGroup>
</s:View>
And the result:
Awesome. I bet you didn't know I was such a good designer, did you? As I said, this solution may not be 100% accurate across all situations, and there may be other ways of doing this, but I hope this is helpful to others.