The amazing adventures of Doug Hughes

I’ve been blogging about different styling issues within the Flex framework. I’d like to take a second to touch on a fairly common issue when trying to style item renderers.

Item renderers are extremely helpful with memory management. As a user scrolls through a list the the flash player only has to instantiate a handful of item renderers that are showing (and a few buffer instances above and below). This recycling is a mixed blessing. As a developer, we have to keep in mind that the item renderer isn’t really being created each round and if we style a certain item renderer based on data we need to remember to double check it each time the data changes. You’ll often see issues arise with icons or style changes within a item renderers when they are being recycled (scrolling). In the following example I’ve got a set of data and the negative numbers are suppose to be styled red.

Item Renderer Code:

package {
    import mx.containers.Canvas;
    import mx.controls.Label;
    import mx.controls.listClasses.BaseListData;
    import mx.controls.listClasses.IDropInListItemRenderer;
    import mx.core.ScrollPolicy;
    public class SampleItemRenderer extends Canvas implements IDropInListItemRenderer {
        protected
        var redLabel: Label = new Label();
        protected
        var negative: Boolean;
        protected
        var regularLabel: Label = new Label();
        protected
        var _listData: BaseListData;

        public
        function SampleItemRenderer() {}

        /**
         *  override public set data.  If it's differnt check if it's
         * less than zero and set view accordingly.
         */
        override public
        function set data(value: Object): void {
            if (value != super.data) {
                super.data = value;
            }
        }

        override protected
        function createChildren(): void {
            super.createChildren();
            this.addChild(regularLabel);
            this.addChild(redLabel);
            redLabel.x = 10;
            regularLabel.x = 10;
            setStyles();
        }

        protected
        function setStyles(): void {
            /set light red color
  redLabel.setStyle('color', 0xFF8888);
  this.verticalScrollPolicy = ScrollPolicy.OFF;
  this.horizontalScrollPolicy = ScrollPolicy.OFF;
  }

  /----------------------------------/  listData
  /----------------------------------

            /**
             *  Implements the <code>listData</code> property
             *  using setter and getter methods.
             */
            public
            function get listData(): BaseListData {
                return _listData
            }

            /**
             *  @private
             */
            public
            function set listData(value: BaseListData): void {
                if (value != _listData) {
                    _listData = value;
                    redLabel.text = _listData.label;
                    regularLabel.text = _listData.label;
                    if (Number(regularLabel.text) < 0) {
                        negative = true;
                    }
                    redLabel.visible = negative;
                    regularLabel.visible = !negative;
                }
            }

        }
    }

Two things are interesting to point out here. The first is a little counter intuitive, but it’s actually more efficient to have two labels and toggle the visibility (and the includeInLayout property if needed). Calling setStyle is fairly resource heavy. (This is also a good trick if changing icon images)

The next gotcha is to always remember to reset the style correctly. In our case if the data is a number that is NOT less then 0 we still need to make changes to this item renderer. This will cover the case when a recycled red renderer needs to be changed back to white.

Here’s the CSS I used for the above example:

DataGrid {
    border-skin: Embed(source="assets /DataGrid_borderSkin.png",
    scaleGridLeft="8", scaleGridTop="8", scaleGridRight="95", scaleGridBottom="95");
    color: #fff;
    column-drop-indicator-skin: Embed(source="assets /DataGrid_columnDropIndicatorSkin.png");
    column-resize-skin: Embed(source="assets /DataGrid_columnResizeSkin.png");
    header-colors: #666, #000;
    roll-over-color: #555;
    selection-color: #777;
    stretch-cursor: Embed(source="assets /DataGrid_stretchCursor.png");
}
mx:DataGrid id="dataGrid" dataProvider=" {
    sampleData;
}
" x="25" y="25" backgroundAlpha="0" headerHeight="25";
dropEnabled="true" borderStyle="solid" itemRenderer="SampleItemRenderer";
height="200" filters=" {
    [new GlowFilter(0x000000, 1, 6, 6, 2, 1, true),
    new GlowFilter(0x000000, .25, 45, 45, 2, 1, false)];
}

Anyone else have tricks they’d like to share for making renderers more efficient? Maybe flagging the display change and calling invalidate display list or avoiding the Canvas container?

Comments on: "Styling Item Renderers in the DataGrid" (4)

  1. “The first is a little counter intuitive, but it’s actually more efficient to have two labels and toggle the visibility”

    If your looking for optimun performnce I belive setting BlendMode.Erase is faster than toggling visible.

    Like

  2. Hi,

    I’m trying to figure out the way to use a background image for the row on rollover ?
    any hint ?

    Like

  3. Hey Pierre,

    Sounds like a custom item renderer might give you what you are looking for.

    The data grid has a style called backgroundImage but I think it’s for the entire background and not row specific.

    If that’s what your looking to change you could always listen for the user to roll over an item then change the style by calling the setStyle(‘backgroundImage’, ‘yourValue’_) method.

    Like

  4. Hi Matt

    Thanks a lot for your answer.
    I don’t get how I can setStyle on a row ??

    Thanks

    Like

Comments are closed.

Tag Cloud

%d bloggers like this: