Post on 15-May-2015
description
Skinning in Flex 4
Saurabh Narulahttp://blog.saurabhnarula.com/
http://twitter.com/saurabhnarula
Agenda
• What is skinning ?
• Skinning in Flex 3
• Major Differences in skinning components in Flex 3 and Flex 4
• Flex 4 Component architecture
• Skinning in Flex 4
• States
• Data
• Skin Parts
• FXG
• CSS changes
• Containers and Layout
• Examples
• Q/A
What is skinning ?
Styling in Flex 3
Styling or Skinning?
Example of skinning in flex 3
A Button Control
State Skin Property
Down DownSkin
over overSkin
up upSkin
disabled disabledSkin
selectedDisabled selectedDisabledSkin
selectedDown selectedDownSkin
selectedOver selectedOverSkin
selectedUp selectedUpSkin
Up over down
1. Create a Skin (types of skins)
graphical skins
programmatic skins
Stateful skins
2. Assign a skin to a component by
style properties (CSS).
3. Set a style property by
MXML tag properties,
the StyleManager class (runtime),
<mx:Style> blocks, or CSS
Demo
Skinning in Flex 3
why a new paradigm of Skinning in Flex 4?
Designer – Developer interaction?
Full fledged, customized look & feel hard to achieve
Expectation of knowledge about how components are structured, should know actionscript
As a result ..
Skinning becomes time consuming
Design requirements change -> more effort to include updates
spend more time in the code to meet the design change
As a result ..
Flex 4!!
Components in Flex 3
In Halo, Components were rigid.
Hard to Extend.
Monkey Patching.
Components in Flex 4
Separation of data, logic, behavior from visuals, states, animation and layout
Write component logic with no assumption about the appearance and vice versa.
MM Architecture inside your component
CCVV
MVC in a button
MM
label:String, selected:Boolean
text field, icon, background
mouse handlers, selection logic
CCVV
MM
CC
VV
Halo
Component
VV
Skin (Background)
Extend the view
MM CC
Spark
Component
VV
Skin (Entire View)
Example: Button with Two icons
Extend viewIconForPhase
Halo
Spark
Extend layoutContents
ActionScript knowledge
Copy MXML from default Button Skin
Two Image tags
Adjust position/size of icons and label
Done! - All MXML!
MM CC
Skin Component Relationship
Component
VV
Skin (Entire View)
Skinning Contract
Flex 4 Skinning Highlights
•All visual aspects, including layout controlled by the skin
•Consistent mechanism
•Formal mechanism – skinning contract
•Declarative control – FXG
Usage Scenarios - User (developer)
A User (developer) wants to change the look and feel of a button
Create a button skin in MXML
MXML can be generated / modified with the help of a tool
No actionscript
Usage Scenarios - Developer (creator)
A Developer create a custom component that he wants to sell to other customers
Extend SkinnableComponent, spark component lifecycle
Skinning this component is now easy
Usage Scenarios - Designer
A Designer wants to earn some extra money
Package Skins into SWC and sell
Change CSS and make use of these skins
Each component contains four conceptual pieces: model, skin, controller, and view-specific logic
Block layout for skinnable component
Skins are associated through CSS
Skinning Contract
association between a component and its skin
A valid contract contains
Skin parts
Skin states
Host Component
Skinning Contract ..
The Component Class must ..
Assign a skin class
Identify the Skin Parts
Identify the Skin States
The Skin Class must ..
Define the Host Component
Declare Skin States, and define their appearance
Define the appearance of the Skin Parts
Demo
Skinning contract in a button
Skinning Contract ..
SkinPart Lifecycle
FXG and MXML Graphics
the new interchange format for the Flash Platform
•Add vector based graphics which scale well
•FXG and MXML Graphics
•FXG is a declarative syntax for defining static graphics
•MXML graphics - collection of classes that you use to define interactive graphics
FXG ..
use a graphics tool such as PhotoShop or Illustrator to export an FXG document
use the FXG document as a component in your Flex application
FXG components are highly optimized
cannot reference instances of objects within the FXG document from the application or other components
Can not add Actionscript or mxml code
Example - <Rect>
MXML Graphics
write MXML graphics code in Flash Builder
add interactivity to MXML graphics - they use classes in the Flex SDK that are subclasses of GraphicElement
result is not as optimized as FXG
MXML graphics, the tags are mapped to their ActionScript equivalent classes
More Control over graphic elements
Example - <s:Rect>
FXG and MXML graphics define the following:
Graphics and text primitives
Fills, strokes, gradients, and bitmaps
Support for filters, masks, alphas, and blend modes
FXG
FXGFXG
FXG FXG
Designer - Developer Workflow
FXG
FXG
FXG
•General path element•Shapes like rectangle , Ellipse•Fine Control over coordinate system, transformation etc.•Scalable Raster effects – filters etc•Based on Flash rendering model•Graphic elements – Shapes ( composed of strait lines, curves), Text, Raster Images•Optimized for flash player•Subset of MXML•Static – no binding, layout, event handlers, styling, etc•compile-time optimization to optimize and compress chunks of FXG content
FXG
Simple Shape primitives (Rectangles, rounded rects, ellipses, circles)
Complex Paths(Linear, Quadratic, and Bezier curve segments)
Full range of fills and strokes (solid, transparent, bitmap, linear and radial gradients)
Masking, filters, blend modes, and more.(blur, glow, dropshadow, screen, multiply…)
Color and 2D transformations(rotate, scale, tint, brighten…)
Integrated text, bitmaps
Demo
Writing a Custom Skinnable component
QoutesBoard ComponentQoutes Board/Group – A Static Part
Qoute – dynamic Part
Label Display – dynamic Part Close Button –
dynamic part
Credits and References
http://opensource.adobe.com/wiki/display/flexsdk/Gumbo#Gumbo-DocumentsandSpecifications
http://www.slideshare.net/rjowen/flex-4-overview
http://weblog.mrinalwadhwa.com/
Questions ?
Thank you.
Saurabh Narulahttp://blog.saurabhnarula.com/
http://twitter.com/saurabhnarula
Reference Slides
• States
• Data
• Skin Parts in Detail
• Advanced CSS selectors
• Containers and Layout
States
<!-- Given the states A,B,C --><m:states>
<m:State name="A"/><m:State name="B"/><m:State name="C"/>
</m:states>
<!-- This button will appear in only states A and B --><Button label="Click Me" includeIn="A, B"/>
<!-- This button will appear in states A and B --><Button label="Button C" excludeFrom="C"/>
<!-- Given the states A,B,C --><m:states>
<m:State name="A"/><m:State name="B"/><m:State name="C"/>
</m:states>
<!-- This button will appear in only states A and B --><Button label="Click Me" includeIn="A, B"/>
<!-- This button will appear in states A and B --><Button label="Button C" excludeFrom="C"/>
•easy to understand and organized markup
• States can be grouped into State Groups
•<fx:Reparent> tag to move children between states
•use invalidateSkinState() and getCurrentSkinState() inside component.
•invalidateSkinState() invalidates the skin state and eventually sets the skin's state to whatever getCurrentSkinState() returns.
•getCurrentSkinState() keep track of current state.
States .. (comparison)
Flex 3 - addchild equivalent
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"><mx:states><mx:State name="newCheckbox"><mx:AddChild relativeTo="{vbox}"><mx:CheckBox id="checkbox" label="Checkbox" /></mx:AddChild></mx:State><mx:State name="newTextArea" basedOn="newCheckBox"><mx:AddChild relativeTo="{vbox}"><mx:TextArea id="textarea" /></mx:AddChild></mx:State></mx:states><mx:VBox id="vbox"><mx:Button label="Click" click="currentState='newCheckbox'" /><mx:Button label="Click" click="currentState='newTextArea'" /></mx:VBox></mx:Application>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"><mx:states><mx:State name="newCheckbox"><mx:AddChild relativeTo="{vbox}"><mx:CheckBox id="checkbox" label="Checkbox" /></mx:AddChild></mx:State><mx:State name="newTextArea" basedOn="newCheckBox"><mx:AddChild relativeTo="{vbox}"><mx:TextArea id="textarea" /></mx:AddChild></mx:State></mx:states><mx:VBox id="vbox"><mx:Button label="Click" click="currentState='newCheckbox'" /><mx:Button label="Click" click="currentState='newTextArea'" /></mx:VBox></mx:Application>
States .. (comparison)
Flex 4 - addchild equivalent
<mx:Application xmlns:mx="library:ns.adobe.com/flex/halo"xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"><m:states><m:State name="default"/><m:State name="newCheckbox"/><m:State name="newTextArea"/></m:states><mx:VBox><mx:Button label="Click" click="currentState='newCheckbox'" /><mx:Button label="Click" click="currentState='newTextArea'" /><mx:CheckBox id="checkbox" label="Checkbox" includeIn="newCheckbox, newTextArea"/><mx:TextArea id="textarea" includeIn="newTextArea"/></mx:VBox></mx:Application>
<mx:Application xmlns:mx="library:ns.adobe.com/flex/halo"xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"><m:states><m:State name="default"/><m:State name="newCheckbox"/><m:State name="newTextArea"/></m:states><mx:VBox><mx:Button label="Click" click="currentState='newCheckbox'" /><mx:Button label="Click" click="currentState='newTextArea'" /><mx:CheckBox id="checkbox" label="Checkbox" includeIn="newCheckbox, newTextArea"/><mx:TextArea id="textarea" includeIn="newTextArea"/></mx:VBox></mx:Application>
States .. (comparison)
Flex 3 - child insertion
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"><mx:states><mx:State name="newTextInput"><mx:AddChild relativeTo="{checkbox1}" position="after"><mx:TextInput id="textinput" /></mx:AddChild></mx:State></mx:states><mx:VBox id="vbox"><mx:CheckBox id="checkbox1" label="One" /><mx:CheckBox id="checkbox2" label="Two" /><mx:Button id="button" label="Click" click="currentState='newTextInput'" /></mx:VBox></mx:Application>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"><mx:states><mx:State name="newTextInput"><mx:AddChild relativeTo="{checkbox1}" position="after"><mx:TextInput id="textinput" /></mx:AddChild></mx:State></mx:states><mx:VBox id="vbox"><mx:CheckBox id="checkbox1" label="One" /><mx:CheckBox id="checkbox2" label="Two" /><mx:Button id="button" label="Click" click="currentState='newTextInput'" /></mx:VBox></mx:Application>
States .. (comparison)
Flex 4 - child insertion
<mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"><m:states><m:State name="default"/><m:State name="newTextInput"/></m:states><mx:VBox><mx:CheckBox label="One" /><mx:TextInput includeIn="newTextInput"/><mx:CheckBox label="Two" /><mx:Button id="button" label="Click" click="currentState='newTextInput'" /></mx:VBox></mx:Application>
<mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"><m:states><m:State name="default"/><m:State name="newTextInput"/></m:states><mx:VBox><mx:CheckBox label="One" /><mx:TextInput includeIn="newTextInput"/><mx:CheckBox label="Two" /><mx:Button id="button" label="Click" click="currentState='newTextInput'" /></mx:VBox></mx:Application>
States .. (comparison)
Flex 3 - A RemoveChild Equivalent
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"><mx:states><mx:State name="noCheckboxes"><mx:RemoveChild target="{checkbox1}" /><mx:RemoveChild target="{checkbox2}" /></mx:State></mx:states><mx:VBox id="vbox"><mx:CheckBox id="checkbox1" label="One" /><mx:CheckBox id="checkbox2" label="Two" /><mx:Button id="button" label="Click" click="currentState='noCheckboxes'" /></mx:VBox></mx:Application>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"><mx:states><mx:State name="noCheckboxes"><mx:RemoveChild target="{checkbox1}" /><mx:RemoveChild target="{checkbox2}" /></mx:State></mx:states><mx:VBox id="vbox"><mx:CheckBox id="checkbox1" label="One" /><mx:CheckBox id="checkbox2" label="Two" /><mx:Button id="button" label="Click" click="currentState='noCheckboxes'" /></mx:VBox></mx:Application>
States .. (comparison)
Flex 4 - A RemoveChild Equivalent
<mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"><m:states><m:State name="default"/><m:State name="noCheckboxes"/></m:states><mx:VBox id="vbox"><mx:CheckBox label="One" excludeFrom="noCheckboxes"/><mx:CheckBox label="Two" includeIn="default"/> <!-- Works as above --><mx:Button id="button" label="Click" click="currentState='noCheckboxes'" /></mx:VBox></mx:Application>
<mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"><m:states><m:State name="default"/><m:State name="noCheckboxes"/></m:states><mx:VBox id="vbox"><mx:CheckBox label="One" excludeFrom="noCheckboxes"/><mx:CheckBox label="Two" includeIn="default"/> <!-- Works as above --><mx:Button id="button" label="Click" click="currentState='noCheckboxes'" /></mx:VBox></mx:Application>
Data
Skin Parts•two types of parts: static and dynamic
•Static parts are instantiated automatically by the skin. There may only be one instance per static part
•Dynamic parts are instantiated when needed, and there may be more than one instance of it
•For eg. for a Scrollbar, you have 4 different static parts: track, thumb, upArrow, downArrow
[SkinPart(required="false"]public var upButton:Button;
•By Default all SkinParts are required, you can make them optional by setting required parameter as false, set true to make SkinPart required
•Dynamic SkinParts – more than one instance of the skin part, accordion can have a dynamic SkinPart as the header for each segment, can be required or optional, variable type is Ifactory.
[SkinPart(type="spark.components.Button")] public var headerFactory:Ifactory;
Defining Skin Parts on the Skin
•Within a skin definition, parts are identified by their id attribute, id attribute is used to bind this element to the component part
•If a required part is not defined by the skin, a runtime error is thrown when the skin is attached to the component.
<Skin><!-- other stuff here... --><MyCustomThumb id="thumb" ... /><!-- other stuff here... --> </Skin>
•Dynamic parts, by convention, live in the Declarations section of the skin file
<Skin><Declarations><Component id="headerFactory"> <MyCustomHeaderControl /> </Component > <!-- More dynamic part definitions can go here... --> </Declarations><!-- Static skin elements and parts go here... --></Skin>
Working with Static Parts
•When loading a skin with static parts, the SkinnableComponent base class is responsible for assigning all static parts from the skin to the declared part variables on the component.
• Once this assignment is done, the component can simply reference the instance variable directly.• •The partAdded() method is called when the variable is assigned. This is where behavior is added to the part.
• The partRemoved() method is called before the skin is unloaded. This is where behavior is removed from the part.
override protected function partAdded(partName:String, instance:*):void{super.partAdded(partName, instance); // For static parts we can just compare the instance with the property if (instance == thumb) thumb.addEventListener(...);}override protected function partRemoved(partName:String, instance:*):void { super.partRemoved(partName, instance); if (instance == thumb) thumb.removeEventListener(...);}
Working with Dynamic Parts
•instantiated by using the createDynamicPartInstance() method and removed using the removeDynamicPartInstance() method.
•The partAdded() and partRemoved() methods are called whenever a dynamic part is added/removed – behaviour is added or removed here.
•There can be many instance of a dynamic part, call createDynamicPartInstance() to create as many as you want.
•loadSkin(). unloadSkin() , lifecycle methods – load and unload the skin
Working with Deferred Parts
•parts that are created at some indeterminate time after the skin has been created. •Components need to be aware that the partAdded() method may be called long after the skin has been instantiated. •An example of a deferred part is one in a TabNavigator that isn't created until the tab is clicked on by the user. When the user clicks on the tab, the part will be created, and through Binding, the SkinnableComponent will become aware of the new part and call partAdded() on it.
public class MyComponent extends SkinnableComponent{// Declare the "details" part[SkinPart]public var details:DetailsPane;
override protected function partAdded(partName:String, instance:*):void{super.partAdded(partName, instance);
if (partName == "details"){// Details part has been created. Attach behaviors here.details.addEventListener(...);details.doSomethingElse();}}}
CSS Changes and Advanced Selectors
CSS Changes and Advanced Selectors ..
Demo
Containers and Layouts
GroupLowest level container in Spark framework
Supports both UIComponents and GraphicElementsOnly the bare essentials:
Layout (through delegates)Containment
Basic Flash player features (transforms, etc.)
DataGroupThe basis of any “List” based container
Anything that uses ItemRenderers
In Spark, everything displayable resides in a Group
Containers and Layouts ..
Containers and Layouts ..
layouts have been separated from the containers
When a Spark container measure() or updateDisplayList() method is called, the task of measurement and child arrangement is promptly delegated to a Spark layout instance
Assignable and custom Layouts
All layout classes extend LayoutBaseVerticalLayout, HorizontalLayout, TileLayout, BasicLayout (Canvas)
Basis of layout for all containers, lists, skins, etc.The goal: clean layout, easy extension, consistent behavior
Big difference: layouts can support transforms
Even though containers support clipping and scrolling, they don't put up scrollbars automatically like Halo does
Containers and Layouts ..
Custom Layout Demo