Lesson 17. Customizing a Flex Application with Skins

In the previous lesson, you learned about using the style API to customize parts of an application. You also learned that there are more customizations that you can make that are unavailable using the style API. In this lesson, you will learn how you can quickly and easily adjust the skins of a Spark component to completely change how that component looks.

image

The FlexGrocer.com application gets an extreme makeover through the use of a few simple skins.

Understanding the Role of Skins in a Spark Component

As you learned in Lesson 12, “Using DataGrids and Item Renderers,” Spark components are built by composition, meaning that the functionality of the components is separated from the look of the component. In this lesson, you will learn how to adjust the look of the components through the use of skins.

In this exercise you will create a skin for the FlexGrocer button on the homepage. Up to this point, this button has simply had the text FlexGrocer on it. You will now modify the skin so it will display the FlexGrocer logo instead.

  1. Open your FlexGrocer project.

    Alternatively, if you didn’t complete the previous lesson or your code is not functioning properly, you can import the FlexGrocer.fxp project from the Lesson17/start folder. Please refer to Appendix A for complete instructions on importing a project should you ever skip a lesson or if you ever have a code issue you cannot resolve.

  2. Right-click the FlexGrocer project, and create a new package named skins.

    image

    This package will hold all the skin classes you create for the application.

  3. Right-click the skins package, and choose New > MXML Skin. Name the skin HomeButtonSkin, set the Host component to spark.components.Button, choose to create it as a copy of spark.skins.spark.ButtonSkin, and then click Finish.

    image

    This will copy the native Spark ButtonSkin class and save it in your skins package under the name HomeButtonSkin. Skins must know the name of the class that they will be skinning, which allows the compiler to verify that all the proper pieces (known as skin-parts) are present in the skin class. If any required skin-parts are missing, a compile-time error will be thrown. If you have any questions on which skin parts are required for a given component, the ActionScript 3.0 Language references has a section for each component listing the skin parts, and whether or not they are required.

    image

    As you can see in the figure, the Button has no required skin parts, which makes skinning a button easy to do.

  4. Remove the Script block from the component, which was automatically added by the compiler.

    The Script block in the component allows for programmatic control over the skinning, and lets you set some aspects of the skin in style sheets. As you will not need this functionality for this skin, it is safe to remove the whole block.

    Tip

    image

    The new MXML skin dialog has a checkbox named Remove ActionScript Styling Code. When checked it effectively deletes the Script block on your behalf.

  5. Remove all the code between the end of the states block and the closing tag for this skin.

    The resulting code for the skin class should look like this (comments from the top of the class have been intentionally omitted):

    image

    What you removed were the various elements that made up a label: the shadow, the fill color, a lowlight color, a highlight color, a highlight stroke, the border, and the label. For the moment, these are extraneous. Later in this lesson you will add some of these elements back.

  6. Between the end of the states block and the closing SparkSkin tag, add a BitmapImage that uses an Embed directive for assets/FlexGrocerButton.png as its source. Specify a horizontalCenter of 0, a verticalCenter of 1, and the alpha in the disabled state as .5.

    <s:BitmapImage source="@Embed('assets/FlexGrocerButton.png')"
       horizontalCenter="0" verticalCenter="1" alpha.disabled=".5"/>

    You have now given this skin a visual look; instead of looking like a typical Flex Button, it will instead use this graphic as its complete look and feel.

  7. Save HomeButtonSkin.mxml. Open FlexGrocer.mxml from the default package.
  8. Find the instantiation of the button labeled Flex Grocer in the controlBarContent node. Add a skinClass attribute with a value of skins.HomeButtonSkin.

    <s:Button label="Flex Grocer" x="5" y="5" click="handleFlexGrocerClick( event )"
       skinClass="skins.HomeButtonSkin"/>

    This code instructs this particular button to use the HomeButtonSkin class as its skin, instead of the class it would have used by default. If you save and run the application now, you will find that the Flex Grocer button you have seen in the top-left corner has been replaced by a graphic, which still responds to users clicks, just as the original button did.

    image

  9. Open FlexGrocer.mxml. Find the List with an id of categoryList. Remove left="200" and replace it with right="171".

    As the FlexGrocer button is now much larger than it was, the List component doesn’t fit properly in the screen, so the category list will be constrained to stay 171 pixels from the right edge of the screen.

  10. To prevent the category list from overlapping the logo if the browser is resized too small, set minWidth="1024" in the top Application tag.

    <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/mx"
       creationComplete="handleCreationComplete(event)"
       xmlns:views="views.*" xmlns:services="services.*"
       xmlns:cart="cart.*"
       minWidth="1024">

One problem still persists with this button. It does not currently feel like a button because as users hover their mouse over it, or click it, it doesn’t change its appearance at all whereas all the other buttons in Flex do. You will correct this problem in the next exercise, as you learn about states and how they relate to skins.

The Relationship between Skins and States

Early in this book, you learned how each Flex component can use different states to allow for adjusting and controlling how a component looks at various times throughout the application. The reality is that the look of the various states can also be modified in the component’s skin as well.

Drawing Programmatically in Flex

The Flex framework offers tools for drawing programmatically: the AS3 Drawing API and FXG Graphics. In both cases, you can use code that instructs Flash Player how to draw graphical elements, rather than simply having it render a binary graphical file (such as JPEG, GIF, or PNG). The benefit of using a programmatic graphic is that it becomes much easier to control and change the graphic in your application than it would be when dealing with any of the binary formats. In most cases, if you wanted to change the color of a binary graphic, you would open that file in a graphics editing program, such as Fireworks or Photoshop, make the changes, and resave the file. When using programmatic graphics, you can simply adjust the properties of the graphical object that is drawing to the screen without having to be familiar with another program.

The AS3 Drawing API uses the graphics property that is native to all instances of the Sprite class in Flash Player. This API includes methods such as moveTo, lineTo, beginFill, endFill, and curveTo, all of which allow developers to draw vector graphics directly on a visual element in Flash Builder.

FXG, on the other hand, allows for XML-based syntax to define graphics, which work well directly inside MXML. In fact, if you were to open any of the Spark skin classes that ship with Flex 4, you would find that all the borders and background colors drawn in any of the Flex components are done with a series of FXG declarations. Even better, many of Adobe’s other tools, such as Photoshop, Illustrator, and Flash Catalyst, export their graphics as FXG, so you can use them directly in your Flex application.

The reality is you can do exactly the same thing with both FXG and the Flash Drawing API. Consider the following, which draws a similar red box with a blue border twice: first with FXG and then with the AS3 Drawing API.

image

image

When this is run, an identical box will be drawn twice, once using the Drawing API’s drawRect() method and setting the lineStyle and fill, and the other time, using the FXG Rect tag, specifying fill and stroke as properties. The real benefit for Flex skinning in using FXG is that the XML markup can easily honor Flex states, so it would become trivial to change the look of the drawing as a user moves their mouse over the rectangle.

image

In this example, two states are defined: a normal and an over state. The state is switched as you move the mouse over or off the rectangle. The fill and stroke of the rectangle are defined to change in the over state. This is how Flex achieves the different looks as the user interacts with the components in an application. If you were to open the spark.skins.spark.ButtonSkin class, you would see a series of rectangles defined that have fills or strokes, which change based on the state (up, over, down, or disabled).

image

For full details on the FXG specification, please see http://opensource.adobe.com/wiki/display/flexsdk/FXG+1.0+Specification.

Customizing Button States with Skins

In this next exercise, you will continue to work with the Skin class you created for the homepage button in the previous exercise and adjust how it looks in other states, such as when the user hovers the mouse over it or clicks on it.

  1. Open HomeButtonSkin.mxml, which you created in the previous lesson.
  2. Between the ending states tag and the Bitmap image tag, define a rectangle (use the Spark Rect class), which has an id of fill, and a value of 1 for the top, bottom, left, and right positioning.

    <s:Rect id="fill" left="1" right="1" top="1" bottom="1">
    </s:Rect>

    This block defines a Rectangle that will fill the component, except for 1 pixel on each of the four sides.

  3. Add a tag pair to specify the fill property of the rectangle.

    <s:Rect id="fill" left="1" right="1" top="1" bottom="1">
       <s:fill>
       </s:fill>
    </s:Rect>

    The fill property of the FXG shapes can accept any element implementing the IFill interface as a value. Among the framework classes that implement this interface are BitmapFill (which uses a graphic as a fill), LinearGradient (which will use a gradient of 2 or more colors as a fill along an axis), RadialGradient (which will use 2 or more colors as a fill, starting from a central point and radiating out to the edges), and SolidColor (which specifies a solid color to use as a fill). In the image here, you can see the four different fills native to the framework. Of course, the IFill interface is a relatively simple one, so you are free to build your own classes that implement it if the framework classes don’t meet your needs.

    image

  4. Populate the fill property with a LinearGradient but add a LinearGradient tag as a child of the fill tag. Specify a rotation of 90 for the gradient.

    <s:Rect id="fill" left="1" right="1" top="1" bottom="1">
       <s:fill>
          <s:LinearGradient rotation="90">
          </s:LinearGradient>
       </s:fill>
    </s:Rect>

    This creates an instance of the LinearGradient class and instructs the gradient to rotate 90 degrees from its standard top-to-bottom approach, so the gradient will appear left to right. All that remains are to instruct the gradient about the elements it will gradate between.

  5. Create as children of the LinearGradient tag two instances of the GradientElement class. Both should have a color of white (#ffffff); the differences will be the colors in the various states. The first Gradient should have an over color of white and a down color of olive green (#afbcac). The second should have a light olive green (#dfecdc) as both the over and down color.

    image

  6. Save and run the application.

    image

    The Flex Grocer button now visually reacts to the users’ gestures, giving them a much clearer indication that they can interact with it.

    Now that you understand how to create a custom skin for a spark button, you are going to create another button skin; this one will be applied to all the other buttons in the application.

  7. Right-click the skins package and choose New > MXML Skin.
  8. Name the skin FlexGrocerButtonSkin, specify spark.components.Button as the Host component, and create it as a copy of spark.skins.spark.ButtonSkin.

    image

  9. In FlexGrocerButtonSkin.mxml, scroll down to the s:Rect tag with the id of fill. Find the first GradientEntry in the LinearGradient. Change the color to be pale green (#f3fbf4), the over color to be a light olive green (#dfecdc), and the down color to be a darker green (#6aa95f). For the second GradientEntry, use a spring green as the color (#d4f1d8) and a light olive green (#dfecdc) for the over and down colors. Leave the default alpha of .85 for both.

    image

    This will allow the buttons to use various greens, in keeping with the color palette of the application.

  10. Delete the next five rectangles.

    The design for the application’s buttons do not require a lowlight, highlight, or highlight stroke.

  11. The next Rect down has an id of border. Remove the child tags for the stroke from the Rect, and replace it with an instance of the SolidColorStroke class. Specify a color of the SolidColorStroke to be mint green (#8eb394) with an alpha of 1 and a disabled alpha of .5.

    image

    Rather than using the complex linear gradient native to the ButtonSkin class, the FlexGrocerButtonSkin simply has a mint green border, which becomes more transparent when disabled.

    There are a few references to the rectangles you removed in the class’s updateDisplayList() method, which must be removed or you will encounter compile-time errors..

  12. Scroll up to the fx:Script block and find the updateDisplayList() method.
  13. Remove the lines that set the radiusX property of the lowlight, highlight, highlightStroke, hldDownStroke1, and hldDownStroke2 rectangles. The revised updateDisplayList() should read like this.

    image

    As those rectangles are no longer in existence, you need to remove any references to them in the code.

    The ButtonSkin is now complete; next you will apply the skin to all Spark Buttons by using the CSS file.

  14. Save and close FlexGrocerButtonSkin, and then open defaultStore.css from the assets directory.
  15. After the end of the s|Application:checkoutView style declaration but before the start of the .cartButton:over declaration, add a new Type Selector for the Spark Button class.

    s|Application:checkoutView {
       backgroundColor: #BBC8B8;
    }
    s|Button{

    }
    .cartButton:over {
       chromeColor: #F3FBF4;
    }

  16. Define a skin-class style property for the Button to use a class reference to the newly created skins.FlexGrocerButtonSkin:

    s|Button{
       skin-class:ClassReference('skins.FlexGrocerButtonSkin'),
    }

    The ClassReference allows the CSS file to provide the StyleManager with a reference to your skin class. As you explore further in Flex, you will find the ClassReference syntax is used any time you are providing an ActionScript class as a value for a style property.

  17. Still in the Spark Button style declaration, specify a color (meaning font color) of #1111b9 and a corner-radius of 5:

    s|Button{
       skin-class:ClassReference('skins.FlexGrocerButtonSkin'),
       color:#1111b9;
       corner-radius:5;
    }

Save the CSS file and run the application. You should find the new look and feel in use throughout the application for buttons that don’t already have their styles set more explicitly.

image

Creating a Skin for the Application

As you might imagine, skins don’t apply only to buttons; larger, more complex components have skins as well. As mentioned earlier in the chapter, each Flex component has its look determined by the skins associated with it, and using the Spark components, you can easily customize any of them.

In this exercise, you will create a skin for the Application component.

  1. Open FlexGrocer.mxml. In the root s:Application tag, add a skinClass attribute. If you use the code-hinting feature, you will find Flash Builder presents you with a list of skins or an option to create a new skin. (If you don’t see the code-hinting, press Ctrl-Spacebar while your cursor is between the open and closing quotes of the attribute.) Choose the Create Skin option.

    image

  2. In the New MXML Skin dialog box, specify skins as the package, FlexGrocerApplicationSkin as the Name, and FlexGrocer as the Host component, and leave the other choices at their default values. Then click Finish and save FlexGrocer.mxml.

    image

    Just like the other skins you created earlier in the lesson, this skin will be created in the skins package, and you will start with the native Spark ApplicationSkin.

  3. In the new FlexGrocerApplicationSkin file, find the Rect just below the comment that reads <!-- layer 0: control bar highlight -->. Remove the LinearGradientStroke being used as the stroke of that Rect, and remove its child tags. In its place add a SolidColorStroke with a light olive green color (#dfecdc):

    <!-- layer 0: control bar highlight -->
    <s:Rect left="0" right="0" top="0" bottom="1" >
       <s:stroke>
          <s:SolidColorStroke color="#dfecdc"/>
       </s:stroke>
    </s:Rect>

    For this application, the gradient stroke is not necessary; instead, a simple solid color stroke in the palette of the application will work fine.

  4. Find the next Rect in the file, which will have the comment <!-- layer 1: control bar fill --> just above it. Change the top attribute from 1 to 32.

    <s:Rect left="1" right="1" top="32" bottom="2" >
       <s:fill>
          <s:LinearGradient rotation="90">
             <s:GradientEntry color="0xEDEDED" />
             <s:GradientEntry color="0xCDCDCD" />
          </s:LinearGradient>
       </s:fill>
    </s:Rect>

    You will soon be adding a different rectangle above the control bar area, so here you are going to limit the background for the control bar area to start 32 pixels from the top of the application.

  5. Still in the control bar fill Rect, remove the LinearGradient (and its child tags) used as the fill, and replace it with a SolidColor with a color value of white (#ffffff).

    <!-- layer 1: control bar fill -->
    <s:Rect left="1" right="1" top="32" bottom="2" >
       <s:fill>
          <s:SolidColor color="#ffffff"/>
       </s:fill>
    </s:Rect>

    Again, the native colors and gradients used as a background for the control bar group of a Flex application does not match the palette for the FlexGrocer application. Instead, a simple solid white background will work better.

  6. Find the next Rect down, which has the comment <!-- layer 2: control bar divider line --> above it. Change the color of the SolidColor fill from black (#000000) to light olive green (#dfecdc).

    <!-- layer 2: control bar divider line -->
    <s:Rect left="0" right="0" bottom="0" alpha="0.55">
       <s:fill>
          <s:SolidColor color="#dfecdc" />
       </s:fill>
    </s:Rect>

    You are once again replacing the default Flex colors with those matching your application.

  7. After the end of the control bar divider line Rect, add a new Rect, with x, y, left, and right attributes set to 0, and a height of 32:

    <s:Rect x="0" y="0" left="0" right="0" height="32">
    </s:Rect>

    This Rect will define a new area above the top navigation, which will house the company’s motto.

  8. Add a fill property to the rectangle. Populate the fill with a LinearGradient rotated 90 degrees. Add two GradientEntries to the LinearGradient. The first GradientEntry should have a Kelly green color (#439235) with an alpha of 1. The second GradientEntry should have a dark Kelly green color (#2E6224) with an alpha of 1.

    <s:Rect x="0" y="0" left="0" right="0" height="32">
       <s:fill>
          <s:LinearGradient rotation="90">
             <s:GradientEntry color="#439235" alpha="1"/>
             <s:GradientEntry color="#2e6224" alpha="1"/>
          </s:LinearGradient>
       </s:fill>
    </s:Rect>

    The gradient fill in this rectangle will act as a background for the FlexGrocer tag line, which will appear at the top of the application.

  9. Just below this rectangle, add a Label, with the text The Freshest, Easiest Way to Buy Groceries. Set the top and right attributes to 10. Specify a color of white (#ffffff) and a 20 point fontSize.

    <s:Label text="The Freshest, Easiest Way to Buy Groceries"
       right="10" top="10"
       color="#ffffff"
       fontSize="20" />

    This label will be positioned in the top-right corner, on top of the gradient green background you created.

  10. Find the Group under the comment <!-- layer 3: control bar -->. Adjust the top attribute to a value of 32.

    <s:Group id="controlBarGroup"
       left="0" right="0"
       top="32" bottom="1"
       minWidth="0" minHeight="0">

    By setting the top value to 32, you ensure the content of the controlGroup will be placed only over the white background, not over the green gradient.

  11. Save FlexGrocerApplicationSkin. Open and run FlexGrocer.

    image

What You Have Learned

In this lesson, you have:

• Learned the relationship between skins and components (pages 406410)

• Worked with states and skins (pages 410413)

• Created two separate Button skins (pages 413419)

• Skinned the FlexGrocer application (pages 419423)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset