Skinning in Flex 4

Post on 15-May-2015

19.052 views 3 download

Tags:

description

Presentation at Adobe Developer Summit 2009 India at Chennai and Hyderabad.

Transcript of Skinning in Flex 4

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