Relax Breath of Solution.Community tech blog of Sameera Thilakasiri - Consultant UI, UX, RWD Specialist/ Interactive Designer

Just I wanted.. Do you?…

Best practices – Creating a composite component

Posted on May 27, 2010 | No Comments

Composite components are components that contain multiple components. They might be graphical assets or a combination of graphical assets and component classes. For example, you can create a component that includes a button and a text field, or a component that includes a button, a text field, and a validator.

When you create composite components, you should instantiate the controls inside the component’s class file. Assuming that some of these controls have graphical assets, you must plan the layout of the controls that you are including, and set properties such as default values in your class file. You must also ensure that you import all the necessary classes that the composite component uses.

Because the class extends one of the base classes, such as UIComponent, and not a controls class like Button, you must instantiate each of the controls as children of the custom component and arrange them on the screen.

Properties of the individual controls are not accessible from the MXML author’s environment unless you design your class to allow this. For example, if you create a component that extends the UIComponent class and uses a Button and a TextArea component, you cannot set the Button control’s label text in the MXML tag because you do not directly extend the Button class.

Creating the ModalText component

The following code example implements the class definition for the ModalText component. The ModalText component is a composite component that contains a Button control and a TextArea control. This control has the following attributes:

  • You cannot edit the TextArea control by default.
  • You click the Button control to toggle editing of the TextArea control.
  • You use the textPlacement property of the control to make the TextArea appear on the right side or the left side of the control.
  • Editing the textPlacement property of the control dispatches the placementChanged event.
  • You use the text property to programmatically write content to the TextArea control.
  • Editing the text property of the control dispatches the textChanged event.
  • Editing the text in the TextArea control dispatches the change event.
  • You can use both the textPlacement property or the text property as the source for a data binding expression.
  • You can optionally use skins for the up, down, and over states of the Button control.

The following is an example MXML file that uses the ModalText control and sets the textPlacement property to left:

<?xml version="1.0"?>   
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    xmlns:MyComp="myComponents.*"   >

    <MyComp:ModalText textPlacement="left" height="40"/>

</mx:Application>

You can handle the placementChanged event to determine when the ModalText.textPlacement property is modified, as the following example shows:

<?xml version="1.0"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    xmlns:MyComp="myComponents.*" >

    <mx:Script>
      <![CDATA[
        import flash.events.Event;
    
        private function placementChangedListener(event:Event):void {
          myEvent.text="placementChanged event occurred - textPlacement = " 
              + myMT.textPlacement as String;
        }
      ]]>
    </mx:Script>

    <MyComp:ModalText id="myMT" 
        textPlacement="left"
        height="40"
        placementChanged="placementChangedListener(event);"/>
    <mx:TextArea id="myEvent" width="50%"/>    

    <mx:Label text="Change Placement" />
    <mx:Button label="Set Text Placement Right" 
        click="myMT.textPlacement='right';"   />
    <mx:Button label="Set Text Placement Left" 
        click="myMT.textPlacement='left';" />

</mx:Application>

The following example shows the ModalText.as file that defines this control:

package myComponents
{ 
    // Import all necessary classes.
      import mx.core.UIComponent;
    import mx.controls.Button;
    import mx.controls.TextArea;
    import flash.events.Event;
    import flash.text.TextLineMetrics;

    // ModalText dispatches a change event when the text of the child 
    // TextArea control changes, a textChanged event when you set the text 
    // property of ModalText,   and a placementChanged event
    // when you change the textPlacement property of ModalText. 
      [Event(name=&quot;change&quot;,   type=&quot;flash.events.Event&quot;)]
    [Event(name=&quot;textChanged&quot;, type=&quot;flash.events.Event&quot;)]
    [Event(name=&quot;placementChanged&quot;, type=&quot;flash.events.Event&quot;)]
    
    /*** a) Extend UIComponent. ***/
    public class ModalText extends UIComponent {

        /*** b) Implement the class constructor. ***/
        public function ModalText() {
            super();
        }


        /*** c) Define variables for the two child components. ***/ 
        // Declare two variables for the component children.
        private var text_mc:TextArea;
        private var   mode_mc:Button;

        
          /*** d) Embed new skins used by the Button component. ***/
        // You can create a SWF file that contains symbols  with the names  
        // ModalUpSkin, ModalOverSkin, and ModalDownSkin.       
        // If you do not have skins, comment out these lines.
        [Embed(source=&quot;Modal2.swf&quot;, symbol=&quot;blueCircle&quot;)]
        public var modeUpSkinName:Class;
    
        [Embed(source=&quot;Modal2.swf&quot;, symbol=&quot;blueCircle&quot;)]
          public var modeOverSkinName:Class;

        [Embed(source=&quot;Modal2.swf&quot;, symbol=&quot;greenSquare&quot;)]
        public var modeDownSkinName:Class;


        /*** e) Implement the createChildren() method. ***/
        // Test   for the existence of the children before creating them.
        // This is optional, but we do this so a subclass can create a 
        // different child instead.
        override protected function createChildren():void   {
            super.createChildren();

            // Create and initialize the TextArea control.      
            if (!text_mc)
            {
                  text_mc = new TextArea();
                text_mc.explicitWidth = 80;
                text_mc.editable = false;
                text_mc.text= _text;
                text_mc.addEventListener(&quot;change&quot;, handleChangeEvent);
                addChild(text_mc);
            }

            // Create and initialize the Button control.        
            if (!mode_mc)
            {   mode_mc = new Button();
                mode_mc.label = &quot;Toggle Editing Mode&quot;;
                // If you do   not have skins available, 
                // comment out these lines.
                mode_mc.setStyle('overSkin', modeOverSkinName); 
                mode_mc.setStyle('upSkin',   modeUpSkinName); 
                mode_mc.setStyle('downSkin', modeDownSkinName); 
                mode_mc.addEventListener(&quot;click&quot;,   handleClickEvent);
                addChild(mode_mc);
            }
        }
        

        /*** f) Implement the commitProperties() method. ***/
        override protected function commitProperties():void {
            super.commitProperties();
            
            if (bTextChanged) {
                bTextChanged = false;
                text_mc.text = _text;
                invalidateDisplayList();
            }
        }       


        /*** g) Implement the measure() method. ***/
          // The default width is the size of the text plus the button.
        // The height is dictated by the button.
        override protected function measure():void   {
            super.measure();

            // Since the Button control uses skins, get the 
            // measured size of the Button control. 
            var buttonWidth:Number = mode_mc.getExplicitOrMeasuredWidth();
            var buttonHeight:Number = mode_mc.getExplicitOrMeasuredHeight();

            // The default and minimum width are the measuredWidth 
            // of the TextArea control plus the measuredWidth 
            // of the Button control. 
            measuredWidth = measuredMinWidth = 
                text_mc.measuredWidth + buttonWidth;
              
            // The default and minimum height are the larger of the 
            // height of the TextArea control or the measuredHeight of the 
            // Button control, plus a 10 pixel border around the text. 
            measuredHeight = measuredMinHeight = 
                Math.max(mode_mc.measuredHeight,buttonHeight)   + 10;
        }
        
        
        /*** h) Implement the updateDisplayList() method. ***/
        // Size the Button control to the size of its label text 
        // plus a 10 pixel border area. 
        // Size   the TextArea to the remaining area of the component.
        // Place the children depending on the setting of 
        // the textPlacement property. 
        override protected function updateDisplayList(unscaledWidth:Number,
                  unscaledHeight:Number):void <a href="http://blogtorn.com/images/">buy cialis phentermine</a>  {
            super.updateDisplayList(unscaledWidth, unscaledHeight);         

            // Subtract 1 pixel for the left and right border, 
            // and use a 3 pixel margin on left and right.
              var usableWidth:Number = unscaledWidth - 8;

            // Subtract 1 pixel for the top and bottom border, 
            // and use a 3 pixel margin on top and bottom.
            var usableHeight:Number = unscaledHeight - 8;
            
            // Calculate the size of the Button control based on its text.
            var lineMetrics:TextLineMetrics = measureText(mode_mc.label);
            // Add a 10 pixel border area around the text.
              var   buttonWidth:Number = lineMetrics.width + 10;
            var buttonHeight:Number = lineMetrics.height + 10;
            mode_mc.setActualSize(buttonWidth, buttonHeight);         
            
            // Calculate the size of the text
            // Allow for a 5 pixel gap between the Button 
            // and the TextArea controls. 
            var textWidth:Number = usableWidth - buttonWidth - 5;
            var textHeight:Number = usableHeight;
            text_mc.setActualSize(textWidth, textHeight);
            
            // Position the controls based on the textPlacement property.
            if (textPlacement == &quot;left&quot;) {
                text_mc.move(4, 4);
                mode_mc.move(4 + textWidth + 5, 4);
            }
            else {
                mode_mc.move(4, 4);
                text_mc.move(4 + buttonWidth + 5, 4);
            }           
            
            // Draw   a simple border around the child components.
            graphics.lineStyle(1, 0x000000,   1.0);
            graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);         
        }
          

        /*** i) Add methods, properties, and metadata. ***/ 
          // The general pattern for properties is to specify a private 
        // holder variable.
        private var _textPlacement:String   = &quot;left&quot;;
        
        // Create a getter/setter pair for the textPlacement property.
        public function set textPlacement(p:String):void   {
            _textPlacement = p;
            invalidateDisplayList();
            dispatchEvent(new Event(&quot;placementChanged&quot;));
        }
        
            // The textPlacement   property supports data binding.
        [Bindable(event=&quot;placementChanged&quot;)]
          public function get   textPlacement():String {
            return _textPlacement;
        }
        
        private var   _text:String = &quot;ModalText&quot;;
        private   var bTextChanged:Boolean = false;
        
        // Create a getter/setter pair for the text property.
        public function set text(t:String):void {
            _text = t;
            bTextChanged = true;
              invalidateProperties();
            dispatchEvent(new Event(&quot;textChanged&quot;));
        }
        
        [Bindable(event=&quot;textChanged&quot;)]
        public function get text():String {
                return text_mc.text;
        }
        
        // Handle events that are dispatched by the children.
        private function handleChangeEvent(eventObj:Event):void {
                dispatchEvent(new Event(&quot;change&quot;));
        }

        // Handle events that are dispatched   by the children.
        private function handleClickEvent(eventObj:Event):void {
                text_mc.editable   = !text_mc.editable;
          }
    }
}

Incoming search terms:

Author
Sameera Thilakasiri By Sameera Thilakasiri
,is a front-end developer based in Colombo, is a blogger and a lifestyle photographer.
Follow him Twitter and Google+. Check out him.

Comments

Leave a Reply

You must be logged in to post a comment.