A Flash Developer Resource Site

Results 1 to 11 of 11

Thread: [RESOLVED] Comprehensive List Component

  1. #1
    Junior Member
    Join Date
    Aug 2008
    Posts
    29

    resolved [RESOLVED] Comprehensive List Component

    Hello,

    I'm trying to create a list like:

    [ icon1 ][ dynamic textfield ][ dynamic textfield ][ another icon1 ]
    [ icon2 ][ dynamic textfield ][ dynamic textfield ][ another icon2 ]
    ...

    But I can't figure out how to do this, adding anything other than a string it will be rendered as "Object xxx", just like trace() does. I also tried DataGrid, but no luck. I guess it's all about cellRenderer, because TileList uses ImageCell to render images, but I don't know how to write a cellRenderer to do what I want. Have been googling for hours, please help..Thanks.

  2. #2
    Senior Member cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    Check this, it may get you further.

    http://flashscript.biz/flashas3/data...lrenderer.html
    - The right of the People to create Flash movies shall not be infringed. -

  3. #3
    Junior Member
    Join Date
    Aug 2008
    Posts
    29
    Thanks, but the tut tells "how to style rows in list using CellRenderer", and I want to know "how to show various contents within a list row" using CellRenderer.

    I have tried using following code as List.cellRenderer:

    Code:
    import fl.controls.Label;
    import fl.controls.listClasses.ICellRenderer;
    import fl.controls.listClasses.ListData;
    import fl.core.InvalidationType;
    import flash.display.Sprite;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import flash.events.Event;
    
    class ItemCellRenderer extends Sprite implements ICellRenderer
    {
    	protected var _data:Object;
    	protected var _listData:ListData;
    	protected var _selected:Boolean;
    
    	/**
    	         * Constructor.
    	         */
    	public function ItemCellRenderer():void
    	{
    		super();
    	}
    
    	/**
    	         * Gets or sets the cell's internal _data property.
    	         */
    	public function get data():Object
    	{
    		return _data;
    	}
    	/** 
    	         * @private (setter)
    	         */
    	public function set data(value:Object):void
    	{
    		_data = value;
    		var loader = new Loader();
    		loader.load(new URLRequest("bear.jpg"));
    		loader.contentLoaderInfo.addEventListener(Event.INIT, tt);
    		function tt(e) {
    			loader.content.width = 44;
    			loader.content.height = 48;
    			addChild(loader.content);
    		}
    
    		x = 5;
    		y = 100;
    
    		var desc = new Label();
    		desc.text = "just a try";
    		addChild(desc);
    	}
    
    	/**
    	         * Gets or sets the cell's internal _listData property.
    	         */
    	public function get listData():ListData
    	{
    		return _listData;
    	}
    	/**
    	         * @private (setter)
    	         */
    	public function set listData(value:ListData):void
    	{
    		_listData = value;
    	}
    
    	/**
    	         * Gets or sets the cell's internal _selected property.
    	         */
    	public function get selected():Boolean
    	{
    		return _selected;
    	}
    	/**
    	         * @private (setter)
    	         */
    	public function set selected(value:Boolean):void
    	{
    		_selected = value;
    	}
    
    	/**
    	         * Sets the internal mouse state.
    	         */
    	public function setMouseState(state:String):void
    	{
    	}
    	public function setSize(width: Number, height: Number):void
    	{
    	}
    	public function setStyle(style:String, value:Object):void
    	{
    	}
    }
    I worked, but it has a problem:

    When the List is vertically longer than it can display (i.e. the vertical scrollbar displays), when scrolling up and down, the Label overlaps each other. I used trace() inside the set data() function and found everytime I scroll, this function is called, so I guess the things are added and loaded multiple times. But why? Anybody knows how to properly write a CellRenderer doing what I wanted?

    Any contribution is greatly appreciated, have been pulling all my hair about this for days...

  4. #4
    Senior Member cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    If you want to show an icon use the iconField property. You can have only one textfield in the list component or you need to use datagrid. But as far as I know you cannot add extra textfields, because they will overlap.
    - The right of the People to create Flash movies shall not be infringed. -

  5. #5
    FK Newb Beater
    Join Date
    Dec 2002
    Location
    Seattle
    Posts
    676
    dz902-

    You are going to want to create a custom cellRenderer for your particular UX. To better understand what went wrong with your cellRenderer, you first have to know how the List component works.

    A cellRenderer is a reusable control that represents a 'chunk' of data from the dataProvider given to the List class. The key term here is reusable. Second, the list only instantiates as many cellRenderers as it needs to fill the viewable area of the control, no more, no less. It's inefficient to create 1000 renderers when the user will view only 6 at a time anyway. So when you see the data() function called several times on your renderer during scrolling, what's happening is the List is removing a rellRenderer that fell outside of the viewable area bounds, push it into an "unusedCellRenderer" array (it does not destroy it, mind you. It just stores it for use later) then pulls any available cellRenderer from that same array to place in the newly scrolled area and gives it a new data 'chunk' to display.

    So, what you see is an overlaped label because you have assumed that your cellRenderer is only given data once when in fact it is given new data every time it is removed from the list and reused. What you should do is code routines that check for previously instantiated children based on your data, destroy them/ remove them and finally layout the renderer based on the new data received from the list.

    I hope this helps, I have done many dozens of cellRenderers in my day for all kinds of data and if you master it, there is noting you can't do with the List Class

    Justin
    Just because you changed the code, doesn't mean it's yours

    Most Recent Work:
    Commercial tanning beds website

  6. #6
    Junior Member
    Join Date
    Aug 2008
    Posts
    29
    Thanks Justin, that helped a lot.

    Now what I did is adding a single line, checking whether the _data is already set, then just return and do nothing:

    Code:
    public function set data(value:Object):void
    {
    	if (_data != null) return; // *newly added*
    
    	...
    }
    It works fine, but there is another problem. When I scroll down through the List, after the 6th item, the item at the bottom of the visible area of the List, became the first item until it is fully visible, i.e.:

    Code:
    At first:
    
    =======LIST=======
    Item 1
    Item 2
    Item 3
    Item 4
    ==================
    
    Scrolling down until the 6th item...
    
    =======LIST=======
    Item 4
    Item 5
    Item 6
    Item 1 (half visible, should be Item 7)
    ==================
    
    Keep scrolling...
    
    =======LIST=======
    Item 4
    Item 5
    Item 6
    Item 7 (fully visible, Item 1 changed to Item 7)
    ==================
    
    Keep scrolling, same thing happens after each item after the 6th one.
    I think it's about caching, but I don't know how to solve the problem, do you have any clue?

    I also tried removing childrens everytime _data is set:

    Code:
    public function set data(value:Object):void
    {
    	// *newly added*
    
    	if (numChildren == 2) {
    		// one for loaded image, one for label
    		removeChildAt(0);
    		removeChildAt(0);
            }
    
    	...
    }
    Very strange this time it does not work, the labels overlaps each other just like before.

  7. #7
    Junior Member
    Join Date
    Aug 2008
    Posts
    29
    Another finding: the method of removing childrens fails only when user scrolls through the list very fast. When use trace() on numChildren, if scrolls at normal pace, it is always 2, but when scrolls very fast, it became much larger numbers.

    Then I tried:

    Code:
    for (var i = 0; i < numChildren; ++i) {
    	removeChildAt(0);
    }
    The labels still overlaps, but not so serious, I guess because the removing process is not fast enough. And I don't think this is the way it should be done (too slow, my Flash crashed after this)...

    So I might stick to the first method, doing everything only once, then the problem is how to deal with caching (or maybe some other problem associated with the first method). Please help...

  8. #8
    FK Newb Beater
    Join Date
    Dec 2002
    Location
    Seattle
    Posts
    676
    It may have to do with your height and width designations after the renderer is instantiated however, there is a more pressing issue with your code:
    PHP Code:
    for (var 0numChildren; ++i) {
        
    removeChildAt(0);

    Should be...
    PHP Code:
    for (var 0numChildreni++) {
        
    removeChildAt(i);

    Just because you changed the code, doesn't mean it's yours

    Most Recent Work:
    Commercial tanning beds website

  9. #9
    Junior Member
    Join Date
    Aug 2008
    Posts
    29
    Quote Originally Posted by Sleeve
    It may have to do with your height and width designations after the renderer is instantiated however, there is a more pressing issue with your code:
    PHP Code:
    for (var 0numChildren; ++i) {
        
    removeChildAt(0);

    Should be...
    PHP Code:
    for (var 0numChildreni++) {
        
    removeChildAt(i);

    the List.rowHeight is set to 50 (including 2px padding), and as you may have seen, the loaded image is resized to 48. Is that what you meant?

    My code was right, buddy...when you remove the first child, the second child became the first. Your code will end up with out of bound error.

    Thanks for the quick reply, please help me about the scrolling issue...

  10. #10
    Junior Member
    Join Date
    Aug 2008
    Posts
    29
    Hello everyone, the problem is solved. What I'm doing now is to set up fixed parts of the cell (sprites, textareas) in the constructor, then, when calling set data(), change the values/contents of those parts accordingly. So instead of removing and adding them, just replace their contents (e.g. TextField.text = "blah").

    And finally I understood how CellRenderer works, many thanks to Justin for the detailed description of the process, and also thanks cancerinform for kind comments.

    Hope this thread to be helpful to other ppl having the same problem...

    Notes FYI:

    1.The removeChildAt() method will not work when user scrolls the list at a fast rate, I guess it is because removeChildAt() takes time to complete, and could be interrupted.

    2.The method of checking if _data is null then return was a mistake from the start. The CellRenderer is reused as Justin points out, so when set data() is called the second time, _data is not null, it contains the previous item, and _data is meant to be set to new item.

    3. My solution: use constructor to set up parts of the cell (their position, dimensions, etc), leave their contents empty. If their dimension cannot be set when the contents are not loaded (e.g. Loader), then, add a listener to do the work. Then in set data() function, replace/change the contents.

    Thanks guys

  11. #11
    Junior Member
    Join Date
    Aug 2008
    Posts
    29
    Apparently, the issue of scrolling at fast rate seemed to be a bug with the Test Movie function of Flash CS3, when using debugger or open the movie in browser, it does not happen.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center