14 Replies Latest reply on Nov 1, 2010 12:33 PM by Mike6679

    HBox ItemRenderer For List Control (how to access HBox instance?)

    Mike6679 Level 1

      Hi ,

       

      I have created a custom Item renderer class that extends the HBox class. This HBox class contains an Image and a Text control.  This "HboxRenderer" class is used as an itemrenderer  in my Main application class by a List control . Now my question is how do I acesss each HBox instance (in each row of the List control) . In other words I need to modify an Image instance (change the source) on a particualr row of the List control.

       

       

      thanks in advance!

       

      -Mike

       

       

      ===================

      Main app

      ==================

       

      [Bindable] private var _listRenderer:ClassFactory;

       

       

       

      private function init():void

      {

      _listRenderer = new ClassFactory(HboxRenderer);

       

             // _listRenderer.properties ={ test: "Hello", test1: "world" };

       

      }

       

       

       

      <mx:List  id="list_questions"

        width="340"

        x="238" y="118"

        height="333"

        itemRenderer="{_listRenderer}"

        dataProvider="{xml_questions.children()}"

        variableRowHeight= "true"

        allowDragSelection="false"

        editable = "false"

        styleName="ListQuestions"

        dragEnabled="true">

       

       

       

      ====================

      renderer

      ===================

       

       

      package com.renderers

      {

      import mx.collections.ArrayCollection;

      import mx.containers.HBox;

      import mx.controls.Image;

      import mx.controls.List;

      import mx.controls.Text;

      import mx.controls.listClasses.BaseListData;

      import mx.controls.listClasses.ListBaseContentHolder;

       

       

      public class HboxRenderer extends HBox implements mx.controls.listClasses.IDropInListItemRenderer

      {

       

            [Embed(source="skin/skin.swf", symbol="Icon_Ask")]

              [Bindable]

              public var icon_ask:Class;

       

       

              [Embed(source="skin/skin.swf", symbol="Icon_ask_grey")]

              [Bindable]

              public var icon_ask_grey:Class;

       

              public var _listData:BaseListData;

      public var list:List;

       

      public var save_array_listItem:Array;

       

       

       

              private var _hbox_cont_img:HBox = null;

      private var _img_ask_icon:Image = null;

      private var _text_listbox_quest:Text = null;

       

      public var row_grey:int=-1;

       

       

       

       

      //-------------------------------------------------

      public function HboxRenderer()

      {

      super();

       

      save_array_listItem = new Array();

      }

      //-------------------------------------------------

      public function newInstance():*

      {

                  return new HboxRenderer();

      }

      //------------------------------------------------

      public function getListData():BaseListData

      {

      return _listData;

      }

      //-------------------------------------------------

      override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void    

              {

                 super.updateDisplayList( unscaledWidth, unscaledHeight );

       

                 //var len:int = ListBaseContentHolder(this.parent).listItems.length;

       

                  width= 340 ;

      setStyle("horizontalGap",-5);

      setStyle("borderStyle","solid");

      setStyle("borderSides","top") ;

      setStyle("borderColor","0xb6a2d0");

       

      var test1:String ="";

       

      /*

      if(row_grey >= 0)

      {

         test1="test";

         //var test:Object = ListBaseContentHolder(this.parent).listItems[row_grey]._img_ask_icon.source = icon_ask_grey;

       

      }

      */

       

       

       

       

      }

      //------------------------------------------------

      override protected function createChildren():void

      {

      super.createChildren();

       

       

      //if(ListBaseContentHolder(this.parent).listItems.length > 0)

      //save_array_listItem = ListBaseContentHolder(this.parent).listItems;

       

       

          //define:

      _hbox_cont_img  = new HBox();

      _img_ask_icon  = new Image();

      _text_listbox_quest  = new Text();

       

       

      //properties:

      _hbox_cont_img.id = "hbox_cont_img";

                  _hbox_cont_img.setStyle("paddingTop",13);

                  _hbox_cont_img.setStyle("paddingLeft", 30);

                  _hbox_cont_img.setStyle("paddingRight", 0);

       

                  _img_ask_icon.id= "img_ask";

                  _img_ask_icon.source = icon_ask;

       

                  _text_listbox_quest. id="text_listBox_question"

                  _text_listbox_quest.styleName = "TextListBox";

                  _text_listbox_quest.width= 267;

                  _text_listbox_quest.setStyle("disabledColor", "0x532F8F");

                  _text_listbox_quest.enabled= false;

       

       

                  //add the children

          this.addChild(_hbox_cont_img);

      _hbox_cont_img.addChild(_img_ask_icon);

      this.addChild(_text_listbox_quest)

      }

              //--------------------------------------------------

      override protected function commitProperties():void

      {

      super.commitProperties();

       

          _text_listbox_quest.text = data.entry.questionfull;

       

          var test:String = data.entry.questionfull;

       

      }

      //---------------------------------------------------

       

      public function get listData():BaseListData

      {

      return _listData;

      }

      //----------------------------------------------------

      public function set listData( value:BaseListData ):void

      {

      _listData = value;

      list = listData.owner as List;

      //list.addEventListener( ListEvent.CHANGE, onListChange, false, 0, true )

      }

       

      }

      }

        • 1. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
          drkstr_1 Level 4

          http://blogs.adobe.com/aharui/2007/03/thinking_about_item_renderers_1.html

           

           

          You need to update some property in your data item, and have that change trigger an update to the image in your List.

          • 2. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
            Mike6679 Level 1

            Thanks for the response! I need to change the row of the list control not based on the dataprovider's data changing. Isn't there another way to access a "row" of a List control?

            • 3. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
              jlgaustin Level 1

              list.dataGroup.elementAt(index), this will give you the instances of your item renderer in the list.  You have to get it via the underlying dataGroup of the list.

              • 4. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                Mike6679 Level 1

                I was able to reference a particular row of the List However, if I change a row's image source  to a second color, when the screen renders again , its set back to the original image which makes sense.  I need a way to **inside the renderer class** to set the image source based on what row its in. How do I do that?? Any one??

                 

                 

                 

                Here is how to acess from parent which doesn't help at all really:

                 

                var hboxObj:HboxRenderer = HboxRenderer(list_questions.indexToItemRenderer(list_questions.selectedIndex));

                           var hbox_container:HBox = HBox(hboxObj.getChildByName("hbox_cont_img"));

                           var img_ask:Image = Image(hbox_container.getChildByName("img_ask"));

                           img_ask.source = icon_ask_grey;

                • 5. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                  krafttimd Level 2

                  I think you need to override the set data function and examine that data to determine which image you display. The key to this approach is to have a property on the underlying data object (i.e. list item) that suggests the correct image to use.

                   

                  override set data(value:Object) : void

                  {

                                  // set the correct image

                                  Image.source = YourDataType(value).whateverPropertyDeterminesTheImage == “X” ? image_x : image_y;

                  }

                   

                  Hope this helps,

                  T.K.

                  • 6. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                    drkstr_1 Level 4

                    This is a common programmer error. See my original post and read that link.

                    • 7. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                      Mike6679 Level 1

                      Thank you krafttimd for making your answer, explicit, clear and to the point and you are correct. I have to keep in mind in Flex,components like the ones I'm creating here, are *Data Driven* and should be handled as such!  Thanks Agian!

                       

                      -Mike

                      • 8. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                        Mike6679 Level 1

                        This now brings forth another issue. Now I have my commitProperties() method, code to deciper from a property set from the parent  and the underlying xml which row icon to set to grey. However , I've learned that say if you set row 0 to grey, the next row (that you scroll to that is not in view with also be set to grey) automatically. How can I set JUST row 0 in a List to grey? hmmmmm.....

                         

                         

                        =======================

                        Parent

                        =======================

                         

                        private function setRowArray(row:int, initial:Boolean = false):void

                        {

                                if(initial)

                                {

                                     for (var idx:int = 0 ; idx < xml_questions.children().length(); ++idx)

                                       arrayRows.addItem("base");

                                }

                                else

                                       arrayRows.setItemAt("grey",row);

                               

                               

                                _listRenderer.properties = { arrayRows: arrayRows};

                        }

                         

                         

                        ===================

                        Custom Component

                        ====================

                        public var arrayRows:ArrayCollection = new ArrayCollection();

                         

                         

                        override protected function commitProperties():void

                        {

                        super.commitProperties();

                         

                         

                        _text_listbox_quest.text = data.entry.questionfull;

                           

                           

                            if(arrayRows[int(data.@id)] == "grey")

                            {

                                   trace("data.entry.questionfull= " + data.entry.questionfull + " data.@id= " + data.@id);

                                   _img_ask_icon.source = icon_ask_grey;

                            }

                        }

                        • 9. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                          krafttimd Level 2

                          I'm a little unclear on what your requirement  "JUST row 0 in a List to grey" is. If you want the first list item, as in the top viewable item as you scroll, to be grey you may want to set a listener for changes to the list data changing. If, on the other hand, you just want to set grey to the first item in the data provider the solution from my previous post should suffice.

                           

                          Hope this helps,

                          T.K.

                          • 10. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                            Mike6679 Level 1

                            Sorry, I don't think I explained myself well.

                            I am setting first item in the list to grey  using the first item in the data provider , to determine this. That is reliable and  works so we are good there. 

                            Now what the the underlying Flex SDK is automatically doing is  setting the first view-able item (or row) in the List to grey as well. So say I have 30 items in my list. Only 10 are view-able at a time. The FIRST item is set to grey (by me). Then I scroll down to the next 10. The Flex SDK is setting the first item in the next 10 (# 11 overall ) to grey as well. and this is also true for when the final 10 are in scrollable view....does this make sense?

                            • 11. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                              krafttimd Level 2

                              I get you now. Your item renderers are being reused by flex in order to increase performance. You might want to try using a factory class to return  new rederers for each line.

                               

                                  import mx.core.IFactory;

                               

                                  public class MyImgItemRedererFactory implements IFactory

                                  {

                               

                                        private var _showGrey:Boolean;

                                        public function set showGrey(show:Boolean) : void // set this value in your tag

                                        {

                                             _showGrey = show;

                                        }

                               

                                      public function newInstance() :*

                                      {

                                          var itemRenderer:MyItemRenderer =  new MyItemRenderer();

                                          itemRenderer.showGrey = showGrey;
                                          return itemRenderer;
                                      }
                                     
                                  }

                               

                              I think this will do the trick for you.

                               

                              T.K.

                              • 12. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                                Mike6679 Level 1

                                How do I incorporate that code in terms  of my existing architecture?  I added your code below but it didn't seem to do anything. I'm sure I'm not doing something right...........

                                 

                                 

                                 

                                ==============

                                In my parent

                                ==============

                                 

                                [Bindable] private var _listRenderer:ClassFactory;

                                 

                                 

                                private function init():void

                                {

                                    _listRenderer = new ClassFactory(HboxRenderer);

                                }

                                 

                                 

                                 

                                <mx:List  id="list_questions"

                                  width="340"

                                  x="238" y="118"

                                  height="333"

                                  itemRenderer="{_listRenderer}"

                                  dataProvider="{xml_questions.children()}"

                                  variableRowHeight= "true"

                                  allowDragSelection="false"

                                  editable = "false"

                                  styleName="ListQuestions"

                                  dragEnabled="true">

                                </mx:List>

                                 

                                 

                                 

                                ================================

                                My Renderer

                                ===============================

                                 

                                 

                                public class HboxRenderer extends HBox implements IFactory

                                {

                                 

                                    [Embed(source="skin/skin.swf", symbol="Icon_Ask")]

                                        [Bindable]

                                        public var icon_ask:Class;

                                 

                                 

                                        [Embed(source="skin/skin.swf", symbol="Icon_ask_grey")]

                                        [Bindable]

                                        public var icon_ask_grey:Class;

                                 

                                          public var _listData:BaseListData;

                                          public var list:List;

                                 

                                 

                                          private var _hbox_cont_img:HBox = null;

                                          private var _img_ask_icon:Image = null;

                                          private var _text_listbox_quest:Text = null;

                                 

                                 

                                          public var arrayRows:ArrayCollection = new ArrayCollection();

                                 

                                 

                                 

                                          private var _showGrey:Boolean;

                                 

                                      public function set showGrey(show:Boolean) : void // set this value in your tag

                                        {

                                              _showGrey = show;

                                        }

                                        //----------------------------------------------------

                                        public function newInstance() :*

                                        {

                                            THIS FUNCTION IS NEVER CALLED

                                            var itemRenderer:HboxRenderer =  new HboxRenderer();

                                            //itemRenderer.showGrey = showGrey;

                                            return itemRenderer;

                                        }

                                • 13. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                                  drkstr_1 Level 4

                                  ...again, read that link I gave you...

                                   

                                  It talks about this exact scenario.

                                   

                                  To quote a specific section:

                                   

                                  Recycling
                                  Custom Item Renderers does take a mental shift from other kinds of UI development in Flex. This is because item renderers need to be completely data-driven, and because they are not mapped to the dataprovider in a one-to-one fashion. A single instance of an item renderer can end up displaying the data of several different items in your data provider. It might display the first item, then the tenth, then the second as you scroll up and down in the DataGrid. We do this for efficiency reasons: if we made a renderer for every item in the data provider it would consume tons of memory. Therefore we only create item renderers that are visible, plus a few others for measurement and buffering. This has the following implications:

                                   

                                  You cannot assume the renderer has been freshly created. When it is time to update the renderer, the components might be holding old values from the item it was rendering before.


                                  You cannot assume that there are only as many renderers created as you see on-screen.


                                  You cannot assume that the first renderer created is for the first visible row.


                                  The most common error I’ve seen is in not resetting values. For example, if you have code that makes the text red if the value is below zero, you might write:

                                   

                                  if (data.price < 0)
                                       setStyle("color", 0xFF0000);
                                  
                                  

                                  This is incorrect. It will work the first time the renderer is created since the default color is black and will work if values are greater than 0, and if the value is less than zero. But once the renderer displays a value less than zero and turns the text red, if it is later asked to renderer a different value that is greater than zero, there is no code to turn the color back to black again. What will happen is that the data will look fine until you start scrolling or receiving updates, then the red will start to appear in funny places. The correct way is to write code like this:

                                   

                                  if (data.price < 0)
                                       setStyle("color", 0xFF0000);
                                  else
                                       setStyle("color", 0x000000);
                                  
                                  

                                  That code will reset the color to black if the price is greater than 0.

                                   

                                  In other words, you cannot rely on instance data. Your item render need to be completely data driven, because any one instance of the renderer could be used to display any data item at any given time.

                                   

                                  You need to tell the renderer through the data if it should have a grey background or not. You also need to make sure that the background changes based on whatever data item is being displayed at that time.

                                  • 14. Re: HBox ItemRenderer For List Control (how to access HBox instance?)
                                    Mike6679 Level 1

                                    I figured it out. It was actually simpler than thought. I just needed to set an item to the original color (explicitly) if it was not marked as grey:

                                     

                                    override protected function commitProperties():void

                                    {

                                    super.commitProperties();

                                     

                                     

                                    _text_listbox_quest.text = data.entry.questionfull;

                                       

                                       

                                        if(arrayRows[int(data.@id)] == "grey")

                                        {

                                          trace("data.entry.questionfull= " + data.entry.questionfull + " data.@id= " + data.@id);

                                          _img_ask_icon.source = icon_ask_grey;

                                        }

                                       else

                                          _img_ask_icon.source = icon_ask;

                                     

                                    }