Tuesday, May 10, 2011

Datefields before Flex 4.5

So I wanted to take advantage of the custom skinning I had already done for a datechooser, and apply that to my new datefield without making a copy of all the skin classes.  Turns out, this is relatively easy, if you know what to look for.  Code below:

  1. Extend datefield
  2. set the dropdownFactory in the constructor to an IFactory var
  3. then in css, set your custom datefielddatechooser's settings (which may be identical or different to your own datechooser custom skins)
  4. and finally, in css (or wherever else you set your styles), for the extended datefield, set the dateChooserStyleName to null...i.e. ClassReference(null)
You do these steps, and you'll have your custom skins show up on the drop down of the datefield...a PITA and Flex 4.0/4.1 problem, so maybe it's no longer mx in 4.5 (but I can't find it anywhere in spark, so maybe it's still stuck in MX hell?).  Anyways, as promised, here are some code examples, if my sytnaxhighlighter doesn't eat them.


package com.lordB8r.view.component.controls.datefield{

import flash.events.Event;
import mx.controls.DateField;
import mx.core.ClassFactory;
import mx.core.IFactory;

public class DateFieldBase extends DateField{
private _dateChooser:IFactory = new ClassFactory(DateFieldDateChooserBase);

public function DateFieldBase(){
this.dropdownFactory = _dateChooser;

package view.component.datefield.datechooser{
 import mx.controls.DateChooser;
 import view.component.datechooser.skins.CommonsDateChooserNextMonthSkin;
 import view.component.datechooser.skins.CommonsDateChooserPrevMonthSkin;
 import view.component.datechooser.skins.CommonsDateChooserRollOverIndicatorSkin;
 import view.component.datechooser.skins.CommonsDateChooserSelectionIndicatorSkin;
 import view.component.datechooser.skins.CommonsDateChooserTodayIndicatorSkin;
 [Style(name="highlightFillColors",  type="Array", arrayType="uint")]

 public class DateFieldDateChooserBase extends DateChooser{
  public function DateFieldDateChooserBase(){
   setStyle("nextMonthSkin",    nextMonthSkin);
   setStyle("prevMonthSkin",    prevMonthSkin);
   setStyle("rollOverIndicatorSkin",  rollOverIndicatorSkin);
   setStyle("selectionIndicatorSkin",  selectionIndicatorSkin);
   setStyle("todayIndicatorSkin",   todayIndicatorSkin);
  protected function get nextMonthSkin():Class{
   return CommonsDateChooserNextMonthSkin;
  protected function get prevMonthSkin():Class{
   return CommonsDateChooserPrevMonthSkin;
  protected function get rollOverIndicatorSkin():Class{
   return CommonsDateChooserRollOverIndicatorSkin;
  protected function get selectionIndicatorSkin():Class{
   return CommonsDateChooserSelectionIndicatorSkin;
  protected function get todayIndicatorSkin():Class{
   return CommonsDateChooserTodayIndicatorSkin;

date-chooser-style-name: ClassReference(null);

datechooser|DateFieldDateChooserBase{ headerColors: #e2e6eb, #f4f5f7; todayColor: #818181; rollOverColor: #b2e1ff; selectionColor: #7fceff; color: #373830; borderColor: #b7babc; headerStyleName:"mydateChooserHeaderStyle"; weekDayStyleName:"mydateChooserWeekDayStyle"; todayStyleName:"mydateChooserTodayStyle"; } .mydateChooserHeaderStyle { color: #373830; font-weight: bold; } .mydateChooserWeekDayStyle { color: #373830; font-weight: bold; } .mydateChooserTodayStyle { color: #ffffff; fontWeight: normal; fontStyle: normal; textDecoration: none; border-visible: false; }

Monday, May 9, 2011

Adding Rollover/rollout halos to Flex 4 skins

So in my current project, I'm working on skinning several controls in Flex 4. One of the issues that I'm coming across is the desire to have the rollover halo effect that used to be in Flex 3. I was getting css styles from the Flex Style Explorer developed several years ago by the Adobe Consulting team.  Now, don't get me wrong, that explorer has saved me many sleepless nights. However those styles no longer apply in Flex 4.  The main reason is that some components no longer extend from button that used to normally extend from button.

ButtonBase.as is fascinating, and a great place to read up and understand the most basic principles of skinning and the skin UIComponent that is attached to the Button.  Flex 4 is wonderful, and I really, really, really enjoy the maintainability of skinning components in this framework much more than the previous framework.

Anyways, the point of this post is to quickly show you how you can take advantage of skin parts, and pre-existing components, to extend your components and get effects that you thought were lost in the transition to Flex 4.

Anyways, if you haven't seen, I think (but can't remember right now) I did a post on passing CSS styles into Flex 4 skins via custom components.  Regardless, you can easily add rollover effects to standard components with a few steps.

  1. Create a new component that extends skinnableComponent

public class ComboBoxBase extends SkinnableComponent{

In that component, add a skinPart.  For more information about skin parts, see Ryan Stewarts quick blog about it here.  That got me going further

public var cbo:ComboBox;

Create a new skin that extends from skinnableComponent

<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009
<!-- host component -->

Add the states you want (mine were hover, hoverNormal, normal)

<s:State name="normal"/>
<s:State name="hover"/>
<s:State name="hoverNormal"/>

Add to the skin the control you want to have a halo around

<s:ComboBox id="cbo" width="100%" height="100%"/>

notice that the combobox here has the exact same ID as in the component class (that is important!)

Add a rect before (or after - depending on the effect you want) with a solidStroke.

<s:Rect left="-1" right="-1" top="-1" bottom="-1" radiusX="3" > 
<s:SolidColorStroke color="0x0000ff" alpha.normal="0" alpha="1"/>

I put my rectangle afterwards, and you can specify radiusX and many other items using script or CSS.

In the custom component, override the partAdded and add some eventlisteners for mouseEvent.ROLL_OVER/ROLL_OUT. (and don't forget to remove them, otherwise some other person might get angry).

override protected function partAdded(partName:String, instance:Object):void{
super.partAdded(partName, instance);
if(instance == cbo){
cbo.addEventListener(MouseEvent.ROLL_OUT, haloEffect);
cbo.addEventListener(MouseEvent.ROLL_OVER, haloEffect);
override protected function partRemoved(partName:String, instance:Object):void{
super.partRemoved(partName, instance);
if(instance == cbo){
cbo.removeEventListener(MouseEvent.ROLL_OUT, haloEffect);
cbo.removeEventListener(MouseEvent.ROLL_OVER, haloEffect);

In your event handler, change the skin.currentState to the new state that you setup in your skin.

protected function haloEffect(me:MouseEvent):void{
if(me.type == MouseEvent.ROLL_OVER){
this.skin.currentState = 'hoverNormal';
//stateChanged('hoverNormal', 'normal', false);
this.skin.currentState = 'normal'

And finally, don't forget to add your skin to your component via setStyle('skinClass', skinClass):

public function ComboBoxBase(){
setStyle('skinClass', skinClass);
protected function get skinClass():Class{
return ComboboxSkin;

And there you have it, a fully haloed Flex 4 component, that you dind't have to do a lot to get...if enough folks want to see the code files, I'll try to find a way to get Blogger to let me post those as well.  Hope this helps someone else

(ps - i apologize for any code syntaxHighlighting formatting problems...I've spent too much time trying to figure out how to do this right now, but if it is really causing someone headaches, please let me know, and I'll spend some more time cleaning it up.  Thanks!)