Flex Tutorial - Change the List Selection Indicator

Skill

Flex Tutorial - Change the List Selection Indicator

Posted in:

Recently we were using a TileList to show a group of images and we wanted to completely change how the selection indicator looked. We wrote the item renderer to handle all of the selection code and the only thing left to do was remove the selection indicator from Flex's TileList control. To our surprise, however, Flex doesn't expose a style or property to do this.

The roll-over indicator can easily be removed by setting the useRollOver style to false. The best Flex offers, style wise, for the selection indicator is the color. I guess a cheap way out would be to set the selection color to the same color as your background. This, however, doesn't work when the background is a gradient or image that is not a solid color.

Here's a simple app that illustrates Flex's default selection indicator. If you click any of those great movies, you'll see the background behind the image turn blue. This is what we're going to remove in this tutorial.

Get Adobe Flash player

After setting every imaginable style and property trying to remove the selection, we eventually began diving into the Flex source code to find a solution. Down in the nitty-gritty of the Flex code, in a file named ListBase.as, we found the culprit. Whenever a list item is selected, the function drawSelectionIndicator is called.

protected function drawSelectionIndicator(indicator:Sprite, x:Number, y:Number,
    width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void
{
   var g:Graphics = Sprite(indicator).graphics;
   g.clear();
   g.beginFill(color);
   g.drawRect(0, 0, width, height);
   g.endFill();
       
   indicator.x = x;
   indicator.y = y;
}

As you can see, there is no way around drawing a background when an item is selected. It simply draws a rectangle using the color set by the selectionColor style.

What we can do, however, is override this function and make it do nothing. To do this, we'll need to make a new TileList that extends the current one. I called mine, TileListEx.

import flash.display.Sprite;
import mx.controls.TileList;
import mx.controls.listClasses.IListItemRenderer;

public class TileListEx extends TileList
{
   override protected function drawSelectionIndicator(indicator:Sprite, x:Number,
       y:Number, width:Number, height:Number, color:uint,
       itemRenderer:IListItemRenderer):void
   {
      return;
   }
}

You can use this class exactly like you would an ordinary TileList except now there will be no selection indicator. Here's the exact same example as above using the extended TileList class.

Get Adobe Flash player

That's it for removing the indicator, but since we overrode the selection indicator function, we can now make it do whatever we want. Here's a quick example on how to make the selection indicator a circle instead of a rectangle.

Get Adobe Flash player

And here's the code to do that.

import flash.display.Graphics;
import flash.display.Sprite;
import mx.controls.TileList;
import mx.controls.listClasses.IListItemRenderer;

public class TileListEx extends TileList
{
   override protected function drawSelectionIndicator(indicator:Sprite, x:Number,
       y:Number, width:Number, height:Number, color:uint,
       itemRenderer:IListItemRenderer):void
   {
      var g:Graphics = Sprite(indicator).graphics;
      g.clear();
      g.beginFill(color);
      g.drawCircle(width / 2, width / 2, width / 2);
      g.endFill();
   
      indicator.x = x;
      indicator.y = y;
   }
}

The sky's the limit when it comes to making the selection indicator look like whatever you want - so go crazy. Hopefully in future releases of Flex, Adobe adds a selection alpha style so developers can easily remove the selection indicator without having to override any functions. Here's a zip file containing the source code from the last example. If you've got any questions, leave a comment.

Justin Winter
02/13/2008 - 23:09

This has bugged me about the TileList for a while. Thanks for posting this.

reply

Ridgeback
03/18/2008 - 05:24

hi. nice example. how about all the images in the tilelist have alpha 0.3 and if I selected/highlight 1 image, the alpha of that image will change to 1.0. In short all the image have alpha 0.3 exept the one that is selected. thanks!

reply

The Fattest
03/18/2008 - 07:07

Ridgeback, I would probably do this in the item renderer. You could hook into the change event for the TileList inside the renderer and then check to see if the selected item is equal to the data of the item renderer then if it is set the alpha to 1 otherwise .3. I could write up a quick example if you need me to.

reply

Ridgeback
03/19/2008 - 04:48

Great! Thanks The Fattest for the quick response. Could you please write some examples. I'm newbie in flex. Again, thank you very much and thanks in advance. Cheers!

reply

Ridgeback
03/26/2008 - 06:19

Hi The Fattest! Can you write up a quick example? Thanks in advance.

reply

The Fattest
03/26/2008 - 07:45

Ridgeback, check out this tutorial and let me know if it covers everything you need.

reply

Ridgeback
04/07/2008 - 02:24

Hi The Fattest,

Sorry for the late response. That was a great tutorial. But how can I apply that to this blog example? I mean this blog example plus the item alpha. This blog example consists of TileListEx.as, MyItemRenderer.mxml, and HideSelection.mxml. How can I apply that without adding another file? I mean just adding the actionscript in the said files. I'm also newbie in actionscript. Thank you very much. And your help is very much appreciated. Cheers!

reply

Ridgeback
05/14/2008 - 00:16

Hi The Fattest, Just want to follow up on this. thanks!

reply

Ridgeback
06/05/2008 - 05:30

Hi again, Any help bout my problem?
thanks...

reply

The Fattest
06/09/2008 - 08:22

Ridgeback, basically you would just use the itemRenderer from the other tutorial and the extended tilelist from this tutorial.

reply

Ridgeback
06/13/2008 - 03:40

Nice, its working now. thanks a lot again for this. Sorry if I'm always making follow up on you. Great job man!

reply

Bill Shirley
04/16/2008 - 16:50

Thanks Brandon.

Of course, ListBase is the parent class of List and DataGrid, as well as TileList. So, this solution will work over there.

I'd point out that Adobe's old-style cast is unnecessary because the indicator parameter was already declared as a Sprite.

var g:Graphics = indicator.graphics;

reply

Greg
05/15/2008 - 17:56

Thanks.
This has been a bother to me as well. The code works well, TY.

gsb

reply

Nice
06/06/2008 - 21:13

Very nice, I was wondering if we can set 5 more pix height and width for each of individual image?

The problem was how to get the image width and height in the TilelistRenderer.

in the override function, it seems doesn't what I want.

itemRenderer.loaderInfo.content.width

Is that possible?

reply

The Fattest
06/09/2008 - 08:22

You can do this in the itemRenderer. Most likely you will have to hook into the load event on the image and then get the height and width out of it.

reply

Deep
06/16/2008 - 06:55

very nicely explained and done...but i have a question..suppose i have a dataprovider for the tilelist(An Array)..now my tile list will display text...i want that when i take the mouse over a text its font size increases...how can we do this??

reply

Nice
06/21/2008 - 13:32

Deep, you may add the zooming effects inside of your itemRenderer component.

reply

Roy Quesada
09/25/2008 - 16:44

Where do you see the flex source code?

drawSelectionIndicator???

reply

The Fattest
09/25/2008 - 16:53

drawSelectionIndicator is the function overidden in the extended TileList class in several of the code blocks. You can also download the source in the zip file in the last paragraph.

reply

The Reddest
09/25/2008 - 16:55

I don't think that's what he meant, The Fattest. I think he wants to know where the actual Flex source code is. I don't remember where it's installed, but I'm sure you do.

reply

The Fattest
09/25/2008 - 17:09

Aye, I got ya. In windows your going to want to look in Program Files/Adobe/Flex Builder 3/sdks/2.0.1/frameworks/source/ or if you have the source for 3.0.0 you can look in sdks/3.0.0/frameworks/source/.

You can also get it from Adobe, http://opensource.adobe.com/wiki/display/flexsdk/Flex+SDK.

reply

Roy Quesada
10/07/2008 - 17:36

wow.
Great, so we can modify all the source of the flex components.

thank you.

reply

DiamondTearz
10/31/2008 - 11:23

Thanks. That worked like a charm. I was trying to do all other kinds of "magic" but just overriding the updateDisplayList was perfect

reply

Stormbreaker
11/19/2008 - 10:18

Or you can just catch the change event and call list.selectedIndex = -1;

reply

Da Bao
12/17/2008 - 08:43

Thanks. Just what I needed. I wonder if they will fix this in the next version of Flex. Skinning can be a right nightmare.

reply

Jonathan R.
02/24/2009 - 16:18

Does anyone know how to remove of the border highlight that appears when using keyboard control? For example, select something in the TileList example above, and then press the left or right arrow key. Notice the thin blue highlight still appearing?

reply

The Reddest
02/24/2009 - 16:23

Although I don't know for sure, that border responds to focus, so I bet there's a method that can be overloaded similar to selection, but for focus.

reply

Jonathan R.
02/24/2009 - 16:33

Good call, The Reddest. It appears that this border is actually the caret indicator, so overriding the drawCaretIndicator method of the ListBase class seems to do the trick, as such:

override protected function drawCaretIndicator(
                    indicator:Sprite, x:Number, y:Number,
                    width:Number, height:Number, color:uint,
                    itemRenderer:IListItemRenderer):void
{
    // hide the focus rectangle      
}

Incidentally, if you set the visible property of the selectionLayer object to false (as below) in the drawSelectionIndicator, then the entire selection is hidden, border and all.

selectionLayer.visible = false;

Thanks again for the suggestion.

reply

The Reddest
02/24/2009 - 16:41

Nice find. I'm working on an app right now where keyboard control will be important. I'll definitely be keeping this in mind.

reply

Jonathan R.
02/24/2009 - 16:37

I forgot to mention that if you set the selectedIndex property to -1, it does bad things to the keyboard control. So, if you want to be able to scroll the list using the keyboard, but not have the highlight on each row, then one of the two methods I posted above seem to work better.

reply

Narendra
04/16/2009 - 15:11

Great example, I am having same problem with my image list and it solved my problem. Thanks

reply

Anonymous
07/15/2009 - 07:32

you could also set enable to false on the TileList. If items are not being dragged or selected!

reply

Trevor-Sonic
07/30/2009 - 10:22

Hi there I found this code VERY usefull. I used this in Flex 3.3.
Also, I needed to change "selection indicator alpha" too. So with inspration of "Jonathan R." I have written this code and it worked well!

I wanted to share with you
Greets!

override public function validateDisplayList():void
{
 super.validateDisplayList();
 selectionLayer.alpha   = .5;
}

reply

Alina Radu
09/15/2009 - 09:35

Thanks, this totally saved my day. I had a DataGrid with rows of different colors and I needed that when selecting a row, to preserve the color but yet to show I selected it. So setting the alpha for the selectionLayer definitely helped me. Thanks again!

reply

lordB8r
08/20/2009 - 13:21

This was very helpful. I have a custom navigator that uses the tileList and object proxy. When navigating my app via either the tileList or a "next" button, the tileList highlight was becoming a issue, but this solution truly rocks. Now the highlight of a button in the tileList is controlled by the css, and I don't get that annoying halo. Thanks again for the great work!

reply

Tee
08/25/2009 - 05:14

I'm not sure if this works for TileList but setting 'selectable' property of List to false would not highlight the selected item

reply

The Fattest
08/26/2009 - 15:49

Right, but I assume that the items are no longer selectable, which would defeat the purpose.

reply

PK
10/28/2009 - 10:03

Excellent post. Very helpful. Thanks much!

reply

jl
01/27/2010 - 01:10

thanks for the post! this has help a lot, but i have one question:
i was wanting to add an image to the selected item so i figured i can just make a style with the image embedded and then just apply the style to the item renderer.

override protected function drawCaretIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void
{
        itemRenderer.styleName = "selectedItemBg";
}

that did apply the image the the selected item but when i clicked on the next item the style was applied to the previous selected item. any idea no what i need to do to make this work.

reply

aswath
02/25/2010 - 07:22

Is it possible to change CSS style in List ItemRenderer.
for example i have one textbox in List ItemRenderer.
I want to change the text color when ever am select the item

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.

Sponsors