Josh
Josh

Reputation: 8159

ItemRenderer Objects Changing Properties

Apologies for the vague title. I could not think of a better way to word it in so few words.

Basically, I am creating a custom ItemRenderer (IR). The IR has a label on the left side and an icon on the right side. The icon on the right side is dynamic (can be either an add or remove icon or nothing at all). This works beautifully and gives me the control I need over it.

Now, the problem is that when I scroll the list in my mobile application, the icons change.

How it should look: enter image description here

How it looks after scrolling using a finger (or mouse in emulator) by dragging on Test3: enter image description here

As you can see, the icons change but the labels do not. I have dragEnabled, dropEnabled, and dragMoveEnabled all set to false on my Spark List component. The only time the icon selection runs is on creationComplete, so there is no way it is choosing a different icon at some point. I can also verify that the data itself is what it should be after this change occurs.

Here is the MXML that creates the item:

<s:HGroup width="100%" verticalAlign="middle" left="{this.sideSpacing}" right="{this.sideSpacing}" top="{this.sideSpacing}" bottom="{this.sideSpacing}">
    <s:Label id="text" width="100%"/>

    <s:Image id="actionIcon" buttonMode="true" click="actionIconClick( event );">
        <s:filters>
            <s:DropShadowFilter alpha=".45" angle="90" distance="3" blurX="3" blurY="3" quality="3"/>
        </s:filters>
    </s:Image>
</s:HGroup>

<s:Rect width="100%" height="1" bottom="0" alpha=".1">
    <s:fill>
        <s:SolidColor color="#000000"/>
    </s:fill>
</s:Rect>

And the possibly over-elaborate AS3 for selecting which icon should be displayed:

private function creationComplete( e:Event ):void {
    if ( this.data.actionIcon != null ) {
        this.actionIconType = this.data.actionIcon;
        if ( this.data.actionIcon == ACTION_ICON_ADD ) {
            this.actionIcon.source = this.addBitmapSource;
        }
        else if ( this.data.actionIcon == ACTION_ICON_REMOVE ) {
            this.actionIcon.source = this.removeBitmapSource;
        }
        else {
            this.actionIcon.source = null;
            this.actionIcon.visible = false;
            this.actionIcon.includeInLayout = false;
        }
    }
    else {
        this.actionIcon.source = null;
        this.actionIcon.visible = false;
        this.actionIcon.includeInLayout = false;
    }
}

What could be causing this issue?

Upvotes: 0

Views: 505

Answers (1)

JeffryHouser
JeffryHouser

Reputation: 39408

Basically, you need to update your renderer's label and icon when the dataChange event is fired. CreationComplete is only fired once. The list isn't really scrolled, just that the data in the itemRenderers change; causing it to look like things are scrolling. I call this renderer recycling.

Here is a component I created for a mobile app that does what you want. It displays a label and an icon (AKA the Decorator). When scrolling the label and icon are both updated. You can use a very similar approach.

<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                    xmlns:s="library://ns.adobe.com/flex/spark"
                    dataChange="onDataChange(event)" alpha=".7" width="100%" cacheAsBitmap="true">
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <fx:Script>
        <![CDATA[
            import com.dotcomit.magondaMaze.managers.BoardDataManager;
            import com.dotcomit.magondaMaze.managers.StatManager;

            import mx.events.FlexEvent;

            [Embed(source="assets/images/chooseLevel/completed78x78.png")]
            private var completedImage:Class;                               

            public var statManager :StatManager = StatManager.instance;     


            protected function onDataChange(event:FlexEvent):void
            {
                var itemAsXML :XML = data as XML;
                var results :String = itemAsXML.@id + '. ' + itemAsXML.@title;
                label = results;
                if( statManager.isBoardComplete(itemAsXML.@id)){
                    this.decorator = completedImage;
                } else {
                    this.decorator = null;
                }
            }
        ]]>
    </fx:Script>
</s:IconItemRenderer>

I'll also add that the IconItemRenderer component--which my code above extends--is designed to do exactly what you need. So, you may not have to re-write the wheel so to speak.

Upvotes: 3

Related Questions