Flex "RadioButton" ListItemRenderer

I'm becoming an ever increasing fan of the way the Flex visual components were built. Yeah, some things are private when protected would be nice, but for the kind of data-focused work I do I find myself rarely getting stuck. On top of that, building Flex widgets is the perfect 3:00AM brain exercise for when our 3 month old daughter wakes me up.

Anyhow, I needed a better way to show long lists of radio buttons in a UI. Using a repeater just kind of stank - I wanted something that worked like a normal list, but showed a RadioButton beside each item. Thirty minutes later, I was in business:

I decided to blog it as it's a dead simple example of how to extend a base Flex component, add additional visual children, and control both the layout and data-focused aspects through the UIComponent "lifecycle" methods and Flex events.

Here's the code for the renderer:

package com.firemoss.controls.list
{
   import mx.controls.RadioButton;
   import mx.controls.listClasses.BaseListData;
   import mx.controls.listClasses.ListBase;
   import mx.controls.listClasses.ListItemRenderer;
   import mx.events.ListEvent;
   
   public class RadioButtonListItemRenderer extends ListItemRenderer
   {
   
      /**
       * Radio button shown at left of control.
       */
      private var radioButton:RadioButton;
      
      /**
       * List owning this renderer.
       */
      private var list:ListBase;
      
      /**
       * Override createChildren() to create a radio button.
       */
      override protected function createChildren():void
      {
         super.createChildren();
         
         // Create our radio button and add it to the display list.          
         this.radioButton = new RadioButton();
         this.addChild(this.radioButton);
      }
      
      /**
       * Override updateDisplayList to position radio button
       * and shift label.
       */
      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
      {
         // Shift what super thinks of width by our radio's width...          
         super.updateDisplayList(unscaledWidth - this.radioButton.width, unscaledHeight);
         
         // For my purposes, a hard width is fine.      
         
         this.radioButton.width = 25;
         
         // Place our radio          
         this.radioButton.x = 6;
         this.radioButton.y = this.height / 2 - this.radioButton.height / 2;

         // Slide that label over          
         this.label.x = this.radioButton.width;
         
      }
      
      /**
       * Override the listData setter to add listener for changes to the owner (List selection change)
       */
      override public function set listData(value:BaseListData):void
      {
         super.listData = value;
         
         // If we're in the right condition          
         if (value.owner is ListBase)
         {
            // Remove event listeners from any prior assigned list             
            if (this.list)
            {
               this.list.removeEventListener(ListEvent.CHANGE, ownerChangeHandler);
            }
   
            // Keep the list around             
            this.list = value.owner as ListBase;
            
            // Watch the list for changes to its selection             
            this.list.addEventListener(ListEvent.CHANGE, ownerChangeHandler, false, 0, true);
         }
      }
      
      
      /**
       * When the list's selection changes, update the state of the radio button.
       */
      private function ownerChangeHandler(event:ListEvent):void
      {
         // If the list has a selection and it's this renderer's data, check the button          
         this.radioButton.selected = (this.data != null && this.data == this.list.selectedItem);
      }
      
   }
}

Enjoy, and happy listing!

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
© 2008 Firemoss, LLC
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.