I checked in some changes to List and ComboBox that allow you to create custom list items. Here’s an example:
[kml_flashembed publishmethod=”static” fversion=”10.0.0″ movie=”http://www.bit-101.com/blog/wp-content/uploads/2010/03/CustomList.swf” width=”250″ height=”200″ targetclass=”flashmovie”]
[/kml_flashembed]
This is enabled through the listItemClass property on List and ComboBox. In it, you pass in a class that must extend the ListItem class. Here’s the code for this example:
[as3]package
{
import com.bit101.components.*;
import flash.display.Sprite;
import flash.events.Event;
public class Playground extends Sprite
{
private var list:List;
private var label:Label;
public function Playground()
{
Component.initStage(stage);
label = new Label(this, 120, 10);
list = new List(this, 10, 10);
list.listItemClass = CheckListItem;
for(var i:int = 0; i < 20; i++)
{
list.addItem({label:"item " + i, checked:i % 2 == 0});
}
list.addEventListener(Event.SELECT, onSelect);
}
protected function onSelect(event:Event):void
{
label.text = list.selectedItem.label + ". checked: " + list.selectedItem.checked;
}
}
}[/as3]
Here, I'm saying list.listItemClass = CheckListItem; We'll see the CheckListItem class shortly. As I add items, I give each one a label property and a checked property, which is true or false. And when an item is selected, I read these properties and assign them to a label.
So here's my custom list item class:
[as3]package
{
import com.bit101.components.CheckBox;
import com.bit101.components.ListItem;
import flash.display.DisplayObjectContainer;
import flash.events.Event;
public class CheckListItem extends ListItem
{
protected var _checkBox:CheckBox;
public function CheckListItem(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0, data:Object = null)
{
super(parent, xpos, ypos, data);
}
protected override function addChildren():void
{
super.addChildren();
_checkBox = new CheckBox(this, 5, 5, "", onCheck);
_label.visible = false
}
public override function draw():void
{
super.draw();
if(_data is String)
{
_checkBox.label = _data as String;
}
else if(_data.label is String)
{
_checkBox.label = _data.label;
}
else
{
_checkBox.label = _data.toString();
}
if(_data.checked != null)
{
_checkBox.selected = _data.checked;
}
}
protected function onCheck(event:Event):void
{
_data.checked = _checkBox.selected;
}
}
}[/as3]
In the addChildren method, I create a CheckBox and turn the existing Label invisible.
In the draw method, I assign the _data.label value to the CheckBox and use _data.checked to set whether it is checked or not. As you can see, there is some additional testing for various possible label values that I basically just copied over from ListItem. When the CheckBox is clicked, it sets _data.checked to its own checked state.
Since data is typed as a generic object, you can pass any property to it. For instance, if you want to display an icon or image, you might pass in an icon class or a url and use that within your list item class to instantiate or load a bitmap and display it.
One thing to note is that any display objects you create in the list item may become the target of mouse click events. In checking for a list selection, the target must be the list item itself, not a child of the list item. For example, notice that when you click the CheckBox, it checks/unchecks the CheckBox, but does not select the list item. You have to click somewhere off the CheckBox to select the item. So if you have any display objects that may be capturing click events, you can set them to mouseEnabled = false, and maybe mouseChildren = false, to have them ignore clicks. The click target will then be the list item itself instead of the child. If you have children that need to be interactive, like the CheckBox in this example, make sure you leave enough space to allow for a selection-causing click as well.
Really amazing…………..
I have a problem Keith. While Resizing, there is big jerk in rendering listitems. Is there any immediate render option?
I’m currently working on rewriting lists completely, so this will not be an issue.
I put the layout logic in “addChildren” function,now its worling fine,before i placed the layout logic in “draw” function. Great work Keith. Waiting for new components……
Was just informed of a bug in the 0.9.6 version of List.as that makes this not work. Checked in a change for it, but if you’re using the zipped source files, you can make this one change in List.as:
public function set listItemClass(value:Class):void
{
_listItemClass = value;
makeListItems(); // add this line
invalidate();
}
Diggin it!
Hi Keith,
this post has helped me out a lot. thank you.
I am running into a problem.
I have created a custom list item that puts 7 radio buttons in the list. I want to be able to react outside when those buttons change state. any idea how I could do that? another architecture solution maybe?
I cannot think of a way to force the list item to change its selection when a radio is clicked, nor can i think of a way of dispatching that information up the tree outside the list. i also cannot access any of the actual ListItem, just the data object for it.
i appreciate any of your thoughts.
thanks
Is there any easy way to group items in the list? or some grouped list component?
Thanks for the framework! saved me so many times 🙂
best regards!
bruno
thanx for this post! and for minimal comps in general! ;D