by Adobe
adobe_logo

Created

28 June 2011

 

Create skins

 
 

@namespace s "library://ns.adobe.com/flex/spark"; (...) s|TextInput.searchInput { skinClass: ClassReference("skins.SearchInputSkin"); } s|Button.searchButton { skinClass: ClassReference("skins.SearchButtonSkin"); }
FlexWebTestDrive.mxml
 
<s:Application ...> (...) <s:TextInput id="searchTxt" prompt="Last Name" styleName="searchInput" .../> <s:Button id="searchBtn" styleName="searchButton" .../> </s:Application>
skins/SearchInputSkin.mxml
 
<?xml version="1.0" encoding="utf-8"?> <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabledStates="0.5" blendMode="normal" minHeight="30"> <fx:Metadata> [HostComponent("spark.components.TextInput")] </fx:Metadata> <fx:Script> <![CDATA[ private static const focusExclusions:Array = ["textDisplay"]; override public function get focusSkinExclusions():Array { return focusExclusions; }; ]]> </fx:Script> <s:states> <s:State name="normal"/> <s:State name="disabled" stateGroups="disabledStates"/> <s:State name="normalWithPrompt"/> <s:State name="disabledWithPrompt" stateGroups="disabledStates"/> </s:states> <s:Rect id="border" left="0" right="0" top="0" bottom="0" radiusX="3" radiusY="3"> <s:stroke> <s:SolidColorStroke id="borderStroke" weight="1" /> </s:stroke> </s:Rect> <s:Rect id="background" left="1" right="1" top="1" bottom="1" radiusX="3" radiusY="3"> <s:fill> <s:SolidColor id="bgFill" color="0xFFFFFF" /> </s:fill> </s:Rect> <s:Rect id="shadow" left="1" top="1" right="1" height="1" radiusX="3" radiusY="3"> <s:fill> <s:SolidColor color="0x000000" alpha="0.12" /> </s:fill> </s:Rect> <s:RichEditableText id="textDisplay" verticalAlign="middle" widthInChars="10" left="10" right="10" top="10" bottom="7" /> <s:Label id="promptDisplay" maxDisplayedLines="1" verticalAlign="middle" mouseEnabled="false" mouseChildren="false" includeIn="normalWithPrompt,disabledWithPrompt" includeInLayout="true" fontStyle="normal" left="10" right="10" top="10" bottom="7"/> </s:SparkSkin>
skins/SearchButtonSkin.mxml
 
<?xml version="1.0" encoding="utf-8"?> <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:assets="assets.*" minHeight="30" minWidth="30"> <fx:Metadata> [HostComponent("spark.components.Button")] </fx:Metadata> <s:states> <s:State name="disabled" /> <s:State name="down" /> <s:State name="over" /> <s:State name="up" /> </s:states> <s:Rect left="0" right="0" top="0" bottom="0" topRightRadiusX="3" topRightRadiusY="3" bottomRightRadiusX="3" bottomRightRadiusY="3"> <s:stroke> <s:SolidColorStroke color="#1A1A1A" weight="1"/> </s:stroke> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="0x999999" color.up="0x666666"/> <s:GradientEntry color="0x4D4D4D" color.up="0x333333"/> </s:LinearGradient> </s:fill> </s:Rect> <assets:search_icon horizontalCenter="0" verticalCenter="0"/> <!-- SkinParts name=iconDisplay, type=spark.primitives.BitmapImage, required=false name=labelDisplay, type=spark.core.IDisplayText, required=false--> </s:Skin>

Tutorial

In this tutorial, you learn to change the appearance of components by creating and using skins. You will skin the TextInput and Button controls used to search the employees. To customize the look and layout of the TextInput control, you create a new skin based on its default skin and then modify it. For the search button, you create a completely new skin and then add graphics to it.
 

 
Step 1: Create a new skin for the TextInput control.

Return to Design mode of FlexWebTestDrive.mxml. Select the searchTxtTextInput control. In the Properties view, click the button next to the Skin field and select Create Skin (see Figure 1). In the New MXML Skin dialog box, set the package to skins and the name to SearchInputSkin; leave the host component set to spark.components.TextInput, create it as a copy of spark.skins.spark.TextInputSkin, and remove the ActionScript styling code (see Figure 2).
 
Figure 1. Create a new skin for the TextInput control.
Create SearchInputSkin as a copy of the default TextInputSkin.
Figure 2. Create SearchInputSkin as a copy of the default TextInputSkin.
In FlexWebTestDrive.mxml, switch to Source mode and look at the TextInput tag. It now has  a skinClass style set to the name of the new skin SearchInputSkin—which currently is the same as the default skin.
 
<s:TextInput id="searchTxt" prompt="Last Name" skinClass="skins.SearchInputSkin" .../>

 
Step 2: Set the skinClass in the style sheet.

Switch back to Design mode and with the TextInput selected, click Convert to CSS. In the New Style Rule dialog box, select Specific component with style name and name it searchInput (see Figure 3). Make this the style used by the search TextInput control in all the application states.
 
Create a class selector for TextInput controls.
Figure 3. Create a class selector for TextInput controls.
The new selector should appear as shown here:
 
s|TextInput.searchInput { skinClass: ClassReference("skins.SearchInputSkin"); }
This class selector can only be applied to TextInput controls.
 
Return to FlexWebTestDrive.mxml and note that styleName has only been set for one of the application states. To set it for all states, modify the source code or select the TextInput control and select Apply Current Properties to All States.
 
Note that instead of creating a class selector and applying it to the one TextInput instance as you did here, you could also have created and used an ID selector.
 

 
Step 3: Review the skin class.

Review the code for SearchInputSkin.mxml.
 
The skin class extends the SparkSkin base class and defines its host component, the component this skin can be applied to:
 
[HostComponent("spark.components.TextInput")]
In the Script block is some code to specify what subcomponents should be excluded when rendering a focus ring for the component.
 
Next, the skin states are defined:
 
<s:states> <s:State name="normal"/> <s:State name="disabled" stateGroups="disabledStates"/> <s:State name="normalWithPrompt"/> <s:State name="disabledWithPrompt" stateGroups="disabledStates"/> </s:states>
You can look up the names of the skin states the skin should contain in the component's API (see Figure 4). Remember you can open a component's API by selecting Help > Dynamic Help, clicking a tag in MXML, and then clicking the API link in the Help view.
 
Navigate to the TextInput skin states in the API.
Figure 4. Navigate to the TextInput skin states in the API.
Next are graphics tags that provide a way to define graphics with MXML tags (see Figure 5). There are multiple Rect tags, which draw rectangles for a border, fill, and shadow for TextInput controls that use this skin. The order in which the elements are defined defines their depth, so the fill rectangle is drawn on top of the border rectangle and the shadow rectangle on top of the fill rectangle.
 
 Review the graphics code.
Figure 5. Review the graphics code.
At the end of the code are RichEditableText and Label controls. The RichEditableText control is the part of the TextInput component that holds and displays the input value. It is called a skin part and is a subcomponent of the TextInput control. The text property of the RichEditableText skin part gets set (in the TextInput component source code) to the text property of the TextInput control, which can be set programatically or by user input. The various attributes of the RichEditableText control specify where the RichEditableText should appear in the TextInput control; in this case, it is vertically aligned, with at least 1 pixel from the top, bottom, right, and left edges of the TextInput control. You modify these values to change where the RichEditableText control is displayed within the TextInput control.
 
<s:RichEditableText id="textDisplay" verticalAlign="middle" widthInChars="10" left="1" right="1" top="1" bottom="1" />
The Label control is the skin part of the TextInput component that holds and displays the optional prompt value. The  text property of the Label skin part is set (in the TextInput component source code) to the prompt property of the TextInput control. Just as for the RichEditableText skin part, you can set various attributes of the Label control to specify where the prompt Label should appear in the TextInput control.
 
<s:Label id="promptDisplay" maxDisplayedLines="1" verticalAlign="middle" mouseEnabled="false" mouseChildren="false" includeIn="normalWithPrompt,disabledWithPrompt" includeInLayout="false"/>
Note, the id values assigned to the two controls:textDisplay and promptDisplay. These are the names assigned to the subcomponents (the skin parts) defined and referenced in the host component's source code, in this case, the TextInput control. In order for you to specify the look and layout of the skin parts, you must use the id's assigned and used by the host component. You can look up the names and types of the skin parts you can reference in a component skin in the component's API (see Figure 6).
 
Navigate to the TextInput skin parts in the API.
Figure 6. Navigate to the TextInput skin parts in the API.

 
Step 4: Change the control's spacing.

In the SparkSkin tag, set minHeight to 30. In the RichEditableText tag, change the left, right, and top properties to 10 pixels and its bottom property to 7. Add these same values to the Label control and also set the includeInLayout property to true and set its fontStyle to normal.
 
Your code should appear as shown here:
 
<s:SparkSkin minHeight="30" ...> (...) <s:RichEditableText id="textDisplay" verticalAlign="middle" widthInChars="10" left="10" right="10" top="10" bottom="7" /> <s:Label id="promptDisplay" maxDisplayedLines="1" verticalAlign="middle" mouseEnabled="false" mouseChildren="false" includeIn="normalWithPrompt,disabledWithPrompt" includeInLayout="true" left="10" right="10" top="10" bottom="7" fontStyle="normal"/> </s:SparkSkin>

 
Step 5: Round the control's corners.

To each of the three Rect tags, add radiusX and radiusY properties set to 3 pixels.
 
Example code for one of the rectangles is shown here:
 
<s:Rect left="0" right="0" top="0" bottom="0" id="border" radiusX="3" radiusY="3"> <s:stroke> <s:SolidColorStroke id="borderStroke" weight="1" /> </s:stroke> </s:Rect>
Run the application and/or switch to Design mode for FlexWebTestDrive.mxml. The search TextInput control should now be larger, have rounded corners, and the prompt should no longer be italic (see Figure 7).
 
View the skinned TextInput control.
Figure 7. View the skinned TextInput control.
Next, skin the search button.
 

 
Step 6: Create a new Button skin file.

Return to Design mode of FlexWebTestDrive.mxml.Select the Search button and in the Properties view, click the button next to the Skin field and select Create Skin. In the New MXML Skin dialog box, create a skin called SearchButtonSkin in the skins package, leave the host component as spark.components.ButtonSkin, and uncheck Create as copy of (see Figure 8).
 
Create SearchButtonSkin.
Figure 8. Create SearchButtonSkin.

 
Step 7: Review the skin class.

In SearchButtonSkin.mxml, switch to Source mode and review the code.
 
The skin class extends the Skin base class and because you specified a host component in the dialog box to create it, the host component is also set:
 
[HostComponent("spark.components.Button")]
The skin states for a Button are also defined:
 
<s:states> <s:State name="disabled" /> <s:State name="down" /> <s:State name="over" /> <s:State name="up" /> </s:states>
Lastly, there is a comment listing the names and types of all the required and optional skin parts so you don’t have to look them up in the API (see Figure 9):
 
<!-- SkinParts name=iconDisplay, type=spark.primitives.BitmapImage, required=false name=labelDisplay, type=spark.core.IDisplayText, required=false -->
Look up the Button skin parts in the API.
Figure 9. Look up the Button skin parts in the API.

 
Step 8: Download the Test Drive assets.

Download and unzip testdrive_assets.zip and add search_icon.fxg to the FlextWebTestDrive project's assets folder. Open assets/search_icon.fxg and review the code (see Figure 10).
 
Add assets/search_icon.fxg to your project and review the code
Figure 10. Add assets/search_icon.fxg to your project and review the code
FXG is a declarative XML syntax for defining vector graphics that closely follows the Flash Player 10 rendering model. This FXG file was created by drawing in Fireworks and then selecting Commands > Export to FXG. You can also create FXG files using Illustrator or Photoshop.
 
In general, you should use an FXG file as a standalone component in your applications. This gives you the greatest amount of memory optimization, and lets you reuse your FXG files in other parts of the same application, or in other applications. In addition, by keeping the FXG file separate from the application, you can edit and export the FXG again from a graphics tool.
 
Although you can resize and animate the entire FXG component, you cannot modify objects within it at runtime. If you want to reference any of its subobjects, you need to convert the FXG syntax to MXML graphics and use those tags in your application instead.
 

 
Step 10: Add the graphics to the skin.

After the states in SearchButtonSkin.mxml, use Code Assist to select the search_icon FXG class (see Figure 11).
 
 Add the search_icon FXG class.
Figure 11. Add the search_icon FXG class.
By using Code Assist, the namespace assignment was written for you in the Skin root tag: xmlns:assets="assets.*".
 
This tells the compiler where to find this class. You put the FXG file in the assets folder so  assets.* says look for files with the name of the tag in the assets folder.
 
Your skin class should appear as shown here:
 
<?xml version="1.0" encoding="utf-8"?> <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:assets="assets.*"> <fx:Metadata> [HostComponent("spark.components.Button")] </fx:Metadata> <s:states> <s:State name="disabled" /> <s:State name="down" /> <s:State name="over" /> <s:State name="up" /> </s:states> <assets:search_icon/> </s:Skin>
Save the file and then return to FlexWebTestDrive.mxml in Design mode. You should see the search button with the new skin (see Figure 12).
 
View the skinned search button.
Figure 12. View the skinned search button.Figure 13. Position the search controls.

 
Step 11: Size and position the icon.

Return to SparkButtonSkin and set the minHeight and minWidth properties of the Skin class to 30. In the search_icon tag, set the horizontalCenter and verticalCenter properties to 0.
 
<s:Skin xmlns:assets="assets.*" minHeight="30" minWidth="30" ...> (...) <assets:search_icon horizontalCenter="0" verticalCenter="0"/>

 
Step 12: Add a background rectangle.

Above the search_icon tag, add a Rect tag and set its left, right, top, and bottom properties to 0. Set its topRightRadiusX, topRightRadiusY, bottomRightRadiusX, and bottomRightRadiusY properties to 3. Set its stroke property to an instance of the SolidColorStroke class with a color of #1A1A1A.
 
<s:Rect left="0" right="0" top="0" bottom="0" topRightRadiusX="3" topRightRadiusY="3" bottomRightRadiusX="3" bottomRightRadiusY="3"> <s:stroke> <s:SolidColorStroke color="#1A1A1A" weight="1"/> </s:stroke> </s:Rect>
The size of the rectangle is set by setting the left, right, top, and bottom properties to 0. The rectangle will fill the entire area of the button, leaving 0 pixels on each side.
 
The corner curvature is set by the radius properties. The corners on the right side will be rounded, the corners on the left side will be square (because no radii were specified).
 
The rectangle will be outlined with a solid dark line with a thickness of 1 pixel.
 

 
Step 13: Add a gradient fill.

Set the rectangle's fill property to an instance of the LinearGradient class with a rotation of 90. Add a GradientEntry with a color of 0x999999 and a color in the up state of 0x666666. Add a second GradientEntry with a color of 0x4D4D4D and a color in the up state of 0x333333.
 
<s:Rect left="0" right="0" top="0" bottom="0" topRightRadiusX="3" topRightRadiusY="3" bottomRightRadiusX="3" bottomRightRadiusY="3"> <s:stroke> <s:SolidColorStroke color="#1A1A1A" weight="1"/> </s:stroke> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="0x999999" color.up="0x666666"/> <s:GradientEntry color="0x4D4D4D" color.up="0x333333"/> </s:LinearGradient> </s:fill> </s:Rect>
Save the file.
 

 
Step 14: Position the search controls.

Return to Design mode of FlexWebTestDrive.mxml and reposition the search TextInput and Button controls (see Figure 13). Make these the properties for all states.
 
Position the search controls.
Figure 13. Position the search controls.
To set the positions for all states, modify the source code or select each control and select Apply Current Properties to all Components.
 

 
Step 15: Set the skinClass in the style sheet.

With the Search button selected, click Convert to CSS. In the New Style Rule dialog box, select Specific component with style name and name it searchButton (see Figure 14). Return to Design mode of FlexWebTestDrive.mxml and make this the style for all states by right-clicking the search button and selecting Apply Current Properties to All States.
 
Create a searchButton class selector for Button controls.
Figure 14. Create a searchButton class selector for Button controls.
The new selector should appear as shown here:
 
s|Button.searchButton { skinClass: ClassReference("skins.SearchButtonSkin"); }
Run the application (see Figure 15). Enter a last name and click the search button; the controls should work exactly as before—they just have a new look.
 
 Use the skinned search controls.
Figure 15. Use the skinned search controls.
You have now successfully skinned the TextInput and Button controls used to search the employees in the application.
 
In this tutorial, you learned to use skins to change the appearance of components.  You learned to create and modify a skin based on a default component skin and to create and add graphics to a new skin. In the next tutorial you skin the other controls in the application.
 

 
Learn more

 
Documentation: Using Flex 4.5
 
ActionScript 3 Reference
 
Flex Developer Center
 
Documentation: Using Fireworks
 
Documentation: Using Illustrator
 
Documentation: Using Photoshop