May
18

Mobile ItemRenderer in ActionScript (Part 5)

5 comments Posted by: Nahuel Foronda

This is part 5 of my series on item renderers. As you may know, the Mobile Flex Framework does not have a DataGrid, mostly because a DataGrid control uses a lot of real state and the phone has a small screen. But, we have tablets too and a Grid makes complete sense. However, the regular flex DataGrid will not work as it is too heavy for that. We also want gestures and bouncing like the mobile List has. So the workaround is to make an ItemRenderer that mimics a grid.

Grid Renderer

For this example I'm reusing the code of the Application from the previous Twitter example so I will not explain that. Also I'm reusing some of the pieces from the TweetRenderer but changing the layout a lot.

For reference, these are the previous posts: part 1, part 2, part 3 and part 4.

Styles

The main difference from the previous example is that I don't have individual styles for each TextField. Instead, all the fields use the same one. The new thing that I added is the vertical-grid-line-color property used to paint the vertical lines. renderers|TweetGridRenderer

renderers|TweetGridRenderer
{
   padding-left: 15;
   padding-right: 15;
   gap: 20;
   
   min-height: 50;
   vertical-grid-line-color:#aaaaaa;
   font-size: 15;
   color: #555555;
   font-family: _sans;
   separator: Embed(source='/styles/images/separator.png' );
   
   background: Embed(source='/styles/images/background_up.png',
      scaleGridLeft=10, scaleGridTop=20, scaleGridRight=11, scaleGridBottom=21 );
}

renderers|TweetGridRenderer:selected
{
   background: Embed(source='/styles/images/background_down.png',
      scaleGridLeft=50, scaleGridTop=20, scaleGridRight=51, scaleGridBottom=21 );
}

TweetGridRenderer

This class has some similar elements to the TweetRenderer. The main differences are:

  • I added a lineCanvas display object used to paint the vertical lines.
  • I use fix height instead of variable height. The height is set by reading the value from the CSS.
  • I use the same styles for all the fields. Note that we do that when we call TextUtil.createSimpleTextField and pass "this".
  • I changed the layout off all the fields and removed the avatar image.
package renderers
{
   import flash.display.DisplayObject;
   import flash.display.Graphics;
   import flash.display.Shape;
   import flash.text.TextField;
   import utils.TextUtil;
   public class TweetGridRenderer extends BaseRenderer
   {
      protected var userField:TextField;
      protected var nameField:TextField;
      protected var contentField:TextField;
      protected var background:DisplayObject;
      protected var backgroundClass:Class;
      protected var separator:DisplayObject;
      protected var lineCanvas:Shape;
      protected var columnWidth:int
      protected var paddingLeft:int;
      protected var paddingRight:int;
      protected var paddingBottom:int;
      protected var paddingTop:int;
      protected var gap:int;
      
      // Contructor
      public function TweetGridRenderer()
      {
         percentWidth = 100;
      }
      
      // Override Protected Methods
      override protected function createChildren():void
      {
         readStyles();
         setBackground();
         var separatorAsset:Class = getStyle( "separator" );
         if( separatorAsset )
         {
            separator = new separatorAsset();
            addChild( separator );
         }
         userField = TextUtil.createSimpleTextField( this );
         addChild( userField );
         nameField = TextUtil.createSimpleTextField( this )
         addChild( nameField );
         contentField = TextUtil.createSimpleTextField( this );
         addChild( contentField );
         lineCanvas = new Shape();
         addChild( lineCanvas );
         // if the data is not null, set the text
         if( data )
            setValues();
      }
      override protected function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ):void
      {
         var oldColumnWidth:int = columnWidth;
         columnWidth = Math.floor( unscaledWidth / 3 );
         if( columnWidth != oldColumnWidth )
            setValues();
         var textWidth:int = columnWidth - paddingLeft - paddingRight;
         background.width = unscaledWidth;
         background.height = unscaledHeight;
         var textY:int = ( unscaledHeight - userField.textHeight ) / 2;
         userField.x = paddingLeft;
         userField.y = textY;
         TextUtil.adjustTextSize( userField, textWidth );
         nameField.x = columnWidth + paddingLeft;
         nameField.y = textY;
         TextUtil.adjustTextSize( nameField, textWidth );
         contentField.x = columnWidth * 2 + paddingLeft;
         contentField.y = textY;
         TextUtil.adjustTextSize( contentField, textWidth );
         separator.width = unscaledWidth;
         separator.y = layoutHeight - separator.height;
         var g:Graphics = lineCanvas.graphics;
         g.clear();
         g.lineStyle( 1, getStyle( "verticalGridLineColor" ) );
         g.moveTo( columnWidth, 0 );
         g.lineTo( columnWidth, unscaledHeight );
         g.moveTo( columnWidth * 2, 0 );
         g.lineTo( columnWidth * 2, unscaledHeight );
      }
      override protected function measure():void
      {
         measuredHeight = getStyle( "minHeight" );
      }
      protected function setBackground():void
      {
         var backgroundAsset:Class = getStyle( "background" );
         if( backgroundAsset && backgroundClass != backgroundAsset )
         {
            if( background && contains( background ) )
               removeChild( background );   
            backgroundClass = backgroundAsset;
            background = new backgroundAsset();
            addChildAt( background, 0 );
            if( layoutHeight && layoutWidth )
            {
               background.width = layoutWidth;
               background.height = layoutHeight;
            }
         }
      }
      override protected function setValues():void
      {
         var arr:Array = String( data.author.name ).split("(");
         var user:String = String( data.author.name )
         userField.text = arr[0];
         nameField.text = String( arr[ 1 ] ).replace( ")", "" );
         contentField.htmlText = data.content.value;
      }
      override protected function updateSkin():void
      {
         currentCSSState = ( selected ) ? "selected" : "up";
         setBackground();
      }
      protected function readStyles():void
      {
         paddingLeft = getStyle( "paddingLeft" );
         paddingRight = getStyle( "paddingRight" );
         gap = getStyle( "gap" );
      }
   }
}

As you can see this renderer is very similar to the one on our previous example. By making just some adjustments we have a completely new layout. Hope you enjoyed this series on item Renderers.

The source is available for download.

Category: Flex | Mobile |

5 Comments so far

Write yours
mikimi
1. mikimi wrote on September 04, 2011 at 9:27 AM
Hi,
i'm trying to set the HtmlText property with no success to show different colors for the words in a single TextField with no success.why?
mihai
2. mihai wrote on May 07, 2012 at 4:09 AM
when i use 2 o these grids in an app, the background on the second grid remains null and crashes when trying to set it's width
mihai
3. mihai wrote on May 07, 2012 at 4:58 AM
figured it out...i'm such a noob, i was having my css point to just one of the grids, moved it to base render and it's all fine now
karunakar
4. karunakar wrote on May 07, 2012 at 8:54 PM
pls send cairngorm example with clear notes
mihai
5. mihai wrote on May 23, 2012 at 3:01 AM
great post! we should buy you a beer!

Leave your comment

Comment etiquette: As a gesture to those subscribed to this post, please keep your comments relevant to the post.

Your email address will never be displayed.
Email is gravatar enabled.Gravatar are the pictures you see next to the comments. If you like to have one, visit gravatar



Allowed tags:

<code>
All other tags will be shown as such, when in doubt, use the preview.

Leave this field empty:


Preview:

Refresh Preview
1. You wrote on