Hi Dave -
Excellent, excellent question!
Much like how a Spark component owns the skin states (ie: it is the responsibility of the component to put the skin in the proper state), the List component owns the item renderer states. To solve your problem with a skinnable component, you would simply override SkinnableComponent.getCurrentSkinState() so that your component puts the skin in the proper state based on mouse getstures, user data, etc. Though a Spark item renderer is not a skinnable component (it does not derive from SkinnableComponent) it very much acts like one - honoring all of the visual and state contracts that a skinnable component honors. As such, to solve your problem - the correct way is to override ItemRenderer.getCurrentRendererState() to return the correct state the renderer should be in based on the mouse interaction, user data, etc.
So, your custom renderer's getCurrentRendererState() shouldn't return the hovered state since it doesn't seem as if you want to do anything visually to the item renderer when its hovered over.
Overriding ItemRenderer.getCurrentRendererState() is the cleaner and more encouraged approach then overriding currentState setter in your renderer.
PS - I noticed that the ASDoc for ItemRenderer.getCurrentRendererState() is @private, meaning that method does not show up in the AS documentation. Thats a bug! I'll fix it right now, but rest assured, that method is there for you to override. Take a look at it in source and do something similar for your usecase.
Hope that makes sense,
Flex SDK Engineer
Actually, just to be pedantic - the list does not own the item renderer's states. The list sets some properties on the itemRenderer (defined in IItemRenderer). The itemRenderer, in turn, sets its own state based on the value of those properties. Your item renderer gets to change how its states are determined (as Deepa described), or you could implement an itemRenderer that has no states at all by implementing that interface on your own UIComponent.
Deepa, Ely, thanks for your responses. I learned some more from both of you.
I tried both approaches, overriding the getCurrentRendererState() method and building a custom renderer from a UIComponent (in this case, by extending Canvas).
On balance, overriding getCurrentRendererState seemed easier. But it's not exactly intuitive. You have to know ItemRenderer's "built-in" states before adding your own, and also know what getCurrentRendererState does before understanding that you have to override it. (Even if it had appeared in the docs, I'm not sure I would have thought to override it.) Originally I was looking for a property on dataGroup that would prevent the hovered and selected states from getting set. (such as "selectable" and "useRollOver" with the Halo List)
Using a custom component required some trial and error. I started by using a Spark Group. But this doesn't implement IDataRenderer (which makes me think ItemRenderer is the "sanctioned" approach.) So I used Canvas. But if you want to use graphic primitives, you need a Group. So my component ended up something like this:
While I like a lot of the features of the Spark components, I'm finding I have to know a lot about the inner workings of the framework to make use of them.
Thanks Dave, for the feedback - I'm excited to hear it!
Do you think the non-intuitiveness of overriding getCurrentRendererState() could be diminished by having more custom examples of renderers in the documentation and online via blogs and cookbook recipes? We don't have as many code examples yet, that I'd like to see - and we're definitely looking to beef that up for release.
And yes, extending ItemRenderer for your custom renderer is the best-practice (ie: "sanctioned") approach. ItemRenderer already implements the necessary interfaces needed for a renderer to "play nice" in the Spark ecosystem (ie: ite implements IDataRenderer, IItemRenderer, etc). So by extending that and adding in your Canvases or Groups or graphics primitives, you're assured to be able to drop that renderer into any IItemRendererOwner (like a List, DataGroup, SkinnableContainer, etc) and be good to go.
I guess no two people will agree on how best to handle documentation. But here are a few rambling thoughts.
Further examples are always good. However, examples in blogs and cookbooks can also confuse, especially if they take a different approach to things. I generally think that such examples illustrate what you "can" do. I often look to such places for inspiration or help in solving a problem. But I think that "official documentation" should give out stronger guidance of what we "should" do. This should certainly involve examples, but there are other things that help too.
My first port of call is usually to the Language Reference pages. And this is where I'd hope to find any "must follow" guidance. So on the DataGroup reference, there is the line, "You must pass an item renderer to a DataGroup container.". That's what I like to see. But on the ItemRenderer page, there is little guidance on how to use this. Presumably people will want to subclass this a lot. But it doesn't say that you must declare the three states "normal, "selected", and "hovered" in your subclass. And it doesn't indicate how to introduce your own custom states. (I realise the docs here may be unfinished, and as you pointed out, the getCurrentRendererState entry is currently invisible. )
But I guess my main confusion was not expecting ItemRenderer to have these initial built-in states. It seems more geared to Lists and not dataGroups. (But I may not have fully grasped the intent of the dataGroup container yet.) I think I would like to see a base ItemRenderer with no states implemented, and perhaps a subclass called ListItemRenderer which would be essentially like ItemRenderer is now. Then you could provide guidance to subclass the former when implementing a DataGroup where no selection or rollover states are needed, and use the latter in Lists and DataGroups where you do want these states.
Anyway, your help on this was much appreciated, and my DataGroup is working very nicely now.