Creating Class Skins and Icons

The AdvancedTree component allows for any of its skins or icons to be overridden with either symbols in your FLA's Library or through external classes that extend MovieClip. What follows is a step by step for replacing the skins in the tree using ActionScript class files. See Creating Library Skins and Icons for using Library symbols for replacing skins.

All skins and icons must extend MovieClip. For resizable skins, you can either draw your graphics and create a scale9Grid to define how it should be resized, or you can implement a setSize(width:Number, height:Number) to redraw your graphic when the size changes. Any skins that need to define states, like the scroll slider, scroll buttons or selection highlight, should implement a changeState(state:String) method to draw a different state. State names include "_Up", "_Over" and "_Down". Icons with multiple graphics must override MovieClip's gotoAndStop() method and use that to draw each specific graphic. For the open/close and branch icons, graphics include "open" and "closed". The vertical scroll arrow icon needs "up" and "down" graphics. The horizontal scroll arrow icon needs "left" and "right" graphics. All other non-state icons (the leaf, an empty branch) don't need to override gotoAndStop().

The following describes the steps for replacing skins using ActionScript classes. The example, classSkins.fla, can be found in the samples downloaded with the component. These steps create the same result as that found in librarySkins.fla and with the Creating Library Skins and Icons tutorial, so the steps below just show the classes needed to implement the same result.

  1. Create a new Flash ActionScript 3.0 file and set its dimensions to 200x300. Drag an AdvancedTree instance to the stage and set its dimensions to match. Specify an XML file to load in its parameters so that you can see the skins (you can use the bigDataset.xml file included with the download). Set useConnectors to true, the iconBuffer to 2, and publish the file to see how it looks with no skins applied.


  2. First, for a skin that can be assigned when no graphic is desired, we will make an invisible skin. Create a new ActionScript file in the same directory and save it as Invisible.as. Enter the following code.
  3. package {

      import flash.display.MovieClip;

      public class Invisible extends MovieClip {

        public function Invisible() {}

      }

    }

    The class extends MovieClip, but does not draw anything.

  4. Now for a simple single state skin, create a new ActionScript file in the same directory and save it as RoundedRect.as. Enter the following ActionScript.
  5. package {

      import flash.display.MovieClip;
      import flash.geom.Rectangle;

      public class RoundedRect extends MovieClip {

        public function RoundedRect() {
          graphics.clear();
          graphics.beginFill(0x521D1D);
          graphics.drawRoundRect(0, 0, 100, 100, 5, 5);
          graphics.endFill();
          scale9Grid = new Rectangle(10, 10, 80, 80);
        }

      }

    }

    This creates a rounded rectangle that can be resized (because of the scale9Grid). This is all that is needed for a resizable skin with no states.

  6. The next skin is more complex because of the need to define states. It implements both a setSize() method and a changeState() method. Create a new ActionScript file and save it as GradientRoundedRect.as. Enter the following ActionScript.
  7. package {

      import flash.display.GradientType;
      import flash.display.MovieClip;
      import flash.geom.Matrix;

      public class GradientRoundedRect extends MovieClip {

        private var _state:String;
        private var _width:Number;
        private var _height:Number;

        public function GradientRoundedRect() {
          _width = 10;
          _height = 10;
        }

        private function redraw():void {
          graphics.clear();
          drawBorder();
          drawFace();
        }

        private function drawBorder():void {
          graphics.beginFill(0x521D1D);
          graphics.drawRoundRect(0, 0, _width, _height, 5, 5);
          graphics.endFill();
        }

        private function drawFace():void {
          var colors:Array;
          switch (_state) {
            case "_Over":
              colors = [0xD49696, 0xC47575];
              break;
            case "_Down":
              colors = [0x7F2C2C, 0x944E4E];
              break;
            default:
              colors = [0x944E4E, 0x7F2C2C];
          }
          var matrix:Matrix = new Matrix();
          matrix.createGradientBox(_width, _height, Math.PI/2, 2, 2);
          graphics.beginGradientFill(GradientType.LINEAR, colors, [1, 1], [0, 255], matrix);
          graphics.drawRoundRect(2, 2, _width-4, _height-4, 5, 5);
          graphics.endFill();
        }

        public function setSize(width:Number, height:Number):void {
          _width = width;
          _height = height;
          redraw();
        }

        public function changeState(state:String):void {
          _state = state;
          redraw();
        }

      }

    }

    In this class, both the changeState() and setSize(), after changing properties of the class, call a redraw method which redraws both the border and the face. In the drawFace() method, the colors to use are determined by the current state. This skin will now respond to mouse over and down events in addition to its default up state.

  8. Next, we'll create the icon skin for the vertical scrollbar arrow. Create a new ActionScript file and save it as VerticalScrollArrow.as. Enter the following code.
  9. package {

      import flash.display.MovieClip;
      import flash.display.Shape;

      public class VerticalScrollArrow extends MovieClip {

        private var _hit:Shape;

        public function VerticalScrollArrow() {
          _hit = new Shape();
          _hit.graphics.beginFill(0, 0);
          _hit.graphics.drawRect(0, 0, 7, 4);
          _hit.graphics.endFill();
          addChild(_hit);
        }

        override public function gotoAndStop(frame:Object, scene:String=null):void {
          graphics.clear();
          graphics.beginFill(0);
          if (frame == "up") {
            graphics.moveTo(3.5, 0);
            graphics.lineTo(7, 4);
            graphics.lineTo(0, 4);
            graphics.lineTo(3.5, 0);
          } else if (frame == "down") {
            graphics.lineTo(7, 0);
            graphics.lineTo(3.5, 4);
            graphics.lineTo(0, 0);
          }
          graphics.endFill();
        }

      }

    }

    The first thing that is done is that a transparent rectangle is created in the constructor. This MUST be done in order for the tree to be able to center the icon based on its dimensions (if no graphics are drawn, then the icon will be seen to have 0 width and 0 height). In the gotoAndStop() override, either an up arrow or a down arrow is drawn.

  10. For the horizontal scrollbar arrow, create another new ActionScript file and save it as HorizontalScrollArrow.as. Enter the following code.
  11. package {

      import flash.display.MovieClip;
      import flash.display.Shape;

      public class HorizontalScrollArrow extends MovieClip {

        private var _hit:Shape;

        public function HorizontalScrollArrow() {
          _hit = new Shape();
          _hit.graphics.beginFill(0, 0);
          _hit.graphics.drawRect(0, 0, 4, 7);
          _hit.graphics.endFill();
          addChild(_hit);
        }

        override public function gotoAndStop(frame:Object, scene:String=null):void {
          graphics.clear();
          graphics.beginFill(0);
          if (frame == "left") {
            graphics.moveTo(0, 3.5);
            graphics.lineTo(4, 0);
            graphics.lineTo(4, 7);
            graphics.lineTo(0, 3.5);
          } else if (frame == "right") {
            graphics.lineTo(4, 3.5);
            graphics.lineTo(0, 7);
            graphics.lineTo(0, 0);
          }
          graphics.endFill();
        }

      }

    }

  12. The final class is for the open/close icon and follows the same method as the last two icons, except the frames to define as "open" and "closed". Create a new ActionScript file and save it as OpenCloseIcon.as. Enter the following ActionScript.
  13. package {

      import flash.display.MovieClip;
      import flash.display.Shape;

      public class OpenCloseIcon extends MovieClip {

        private var _rect:Shape;
        private var _icon:Shape;

        public function OpenCloseIcon() {
          _rect = new Shape();
          _rect.graphics.beginFill(0);
          _rect.graphics.drawRect(0, 0, 11, 11);
          _rect.graphics.endFill();
          _rect.graphics.beginFill(0xD8AFAF);
          _rect.graphics.drawRect(1, 1, 9, 9);
          _rect.graphics.endFill();
          addChild(_rect);
          _icon = new Shape();
          addChild(_icon);
          gotoAndStop("closed");
        }

        override public function gotoAndStop(frame:Object, scene:String=null):void {
          _icon.graphics.clear();
          _icon.graphics.beginFill(0);
          _icon.graphics.drawRect(3, 5, 5, 1);
          _icon.graphics.endFill();
          if (frame == "closed") {
            _icon.graphics.beginFill(0);
            _icon.graphics.drawRect(5, 3, 1, 5);
            _icon.graphics.endFill();
          }
        }

      }

    }

    This is only slightly more complex in that a rectangle with border and fill is first drawn in the constructor as opposed to the transparent rectangle. These are graphics that will remain constant in the icon. The gotoAndStop() override draws the proper plus or minus icon.

  14. Return to the FLA you created in the first step and add a new layer named "code". Add the following code to map the skins you just created to the tree elements. Styles are also tweaked to match the skins.
  15. import com.flashloaded.ui.tree.graphic.TreeSkins;
    import com.flashloaded.ui.tree.graphic.TreeStyles;

    tree.setSkin(TreeSkins.LEAF_GRAPHIC, Invisible);
    tree.setSkin(TreeSkins.BRANCH_GRAPHIC, Invisible);
    tree.setSkin(TreeSkins.HORIZONTAL_SCROLL_WELL_GRAPHIC, RoundedRect);
    tree.setSkin(TreeSkins.VERTICAL_SCROLL_WELL_GRAPHIC, RoundedRect);
    tree.setSkin(TreeSkins.HORIZONTAL_SCROLL_BACK_GRAPHIC, RoundedRect);
    tree.setSkin(TreeSkins.VERTICAL_SCROLL_BACK_GRAPHIC, RoundedRect);
    tree.setSkin(TreeSkins.INNER_BACK_GRAPHIC, GradientRoundedRect);
    tree.setSkin(TreeSkins.OUTER_BACK_GRAPHIC, GradientRoundedRect);
    tree.setSkin(TreeSkins.HORIZONTAL_SCROLL_BUTTON_GRAPHIC, GradientRoundedRect);
    tree.setSkin(TreeSkins.VERTICAL_SCROLL_BUTTON_GRAPHIC, GradientRoundedRect);
    tree.setSkin(TreeSkins.HORIZONTAL_SCROLL_SLIDER_GRAPHIC, GradientRoundedRect);
    tree.setSkin(TreeSkins.VERTICAL_SCROLL_SLIDER_GRAPHIC, GradientRoundedRect);
    tree.setSkin(TreeSkins.HORIZONTAL_SCROLL_ARROW_GRAPHIC, HorizontalScrollArrow);
    tree.setSkin(TreeSkins.VERTICAL_SCROLL_ARROW_GRAPHIC, VerticalScrollArrow);
    tree.setSkin(TreeSkins.OPEN_CLOSE_GRAPHIC, OpenCloseIcon);

    tree.setStyleProperty(TreeStyles.ICON, 0xFFFFFF);
    tree.setStyleProperty(TreeStyles.ROLLOVER_ICON, 0x000000);
    tree.setStyleProperty(TreeStyles.SELECTED_ICON, 0xFFFFFF);
    tree.setStyleProperty(TreeStyles.TEXT_COLOR, 0xFFFFFF);
    tree.setStyleProperty(TreeStyles.HIGHLIGHT_TEXT_COLOR, 0x000000);
    tree.setStyleProperty(TreeStyles.SELECTED_HIGHLIGHT, 0x521D1D);
    tree.setStyleProperty(TreeStyles.ROLLOVER_HIGHLIGHT, 0xD8AFAF);
    tree.setStyleProperty(TreeStyles.CONNECTOR_LINE_COLOR, 0x000000);

    For a full list of skins that can be set, see TreeSkins class. Styles can be found in TreeStyles class. If you publish your movie now, you will see the new skins applied.