Android: Custom Spinners

This tutorial shows how to replace the default Spinner graphics in a Google Android application.

This is an example of the default Spinner graphics from the default "Dark" theme in the current version of the Android SDK:

Image:Spinner_Example.png

It's nice and big for eventual use with touchscreen hardware, but it kind of looks like the bright orange Hot Wheels car tracks I used to make ramps with as a child. As with the Custom Buttons tutorial, if you want to create any sort of custom UI for your Android application, you're going to want to swap these graphics out with some custom graphics. Especially if your UI isn't orange and gray.

Substituting custom graphics for Spinners follows the same basic method shown in Custom Buttons, but it is a touch more complicated, so you might want to refer to that tutorial first.

Spinner

The Android Spinner is made up of two parts. The first is the larger background image (the part that looks like a Hot Wheels car track) and the other is the selector image, which is the small graphic on the right side with the little arrows in it. The selector image changes depending on whether the Spinner dropdown is showing, and which element in the Spinner list is showing.

Spinner Background

I'll start by showing you how to replace the background graphics. In the current version of the SDK, they're located in android.jar, here:


android.jar\res\drawable-finger\


As I mention in Custom Buttons, a .jar file is just a .zip file with the extension changed to .jar. To view it's contents, just change .jar to .zip, and extract it with your favorite Unzip application. These are the default Dark theme images, stored as compiled Nine-Patch PNG files: :


Image:spinner_normal.9.png spinner_normal.9.png

Image:spinner_press.9.png spinner_press.9.png

Image:spinner_select.9.png spinner_select.9.png


I said it before, and I'll say it again: I love orange. I really do. I'm always the orange piece in Trivial Pursuit. But it just doesn't go with everything, so here's how to substitute your own graphics.

New Background

In creating your new Spinner background graphics, I'd suggest starting with these as a model. Copy them to a working folder, and edit them in your favorite image editor. You'll need to provide your own versions of these three state image files, stored as Nine-Patch PNG files (.9.png). Google Describes how to create a Nine-Patch image here:

http://code.google.com/android/reference/available-resources.html#ninepatch

You can use the Android.jar image files as a starting point, but it's important to realize that these Nine-Patch images have already been compiled into the .jar file, so the borders that specify the stretchable and drawable sections of the image have already been stripped from the file. You'll need to add a 1-pixel wide border around the entire image, and define your own stretchable and drawable sections. This is easy enough to do, so I won't describe it any further here.

Once you've created your new button graphics, just import them into your drawable folder in Eclipse.

You'll then want to create a new XML file in the drawable folder to associate these images with your new Spinner. I've named my XML file myspinner_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"
android:state_pressed="false"
android:drawable="@drawable/myspinner_select" />
<item android:state_focused="true"
android:state_pressed="true"
android:drawable="@drawable/myspinner_press" />
<item android:state_focused="false"
android:state_pressed="true"
android:drawable="@drawable/myspinner_press" />
<item android:drawable="@drawable/myspinner_normal" />
</selector>

The <selector> tag allows you to provide multiple states for the Spinner, just as you did for your Button in Custom Buttons (i.e. normal, focused and pressed). Note the android:state_focused and android:state_pressed properties. The drawables that are associated with those states are the 9.PNG files you imported above, without the ".9.png".

Now to associate this Spinner drawable in your XML layout file, all you have to do is assign it to the android:background property:

<Spinner android:id="@+id/spinner_chemical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:background="@drawable/myspinner_background"/>

Now, depending on what you made your new background graphics look like, you should have a spinner that looks something like this:

Image:Spinner_Example_NewBackground.png

As you can see, I've made my background blue to match the blue background of my application. However, I still have the default orange and gray selector graphic. So, how do I change that?


I'm glad you asked...

The Selector

The selector has a number of states, each with its own image. They're stored in the same place as the Spinner background graphics, and these are the names:


Image:btn_dropdown_down.9.png btn_dropdown_down.9.png

Image:btn_dropdown_left_only.9.png btn_dropdown_left_only.9.png

Image:btn_dropdown_left_right_collapsed.9.png btn_dropdown_left_right_collapsed.9.png

Image:btn_dropdown_neither.9.png btn_dropdown_neither.9.png

Image:btn_dropdown_neither_up_down.9.png btn_dropdown_neither_up_down.9.png

Image:btn_dropdown_right_only.9.png btn_dropdown_right_only.9.png

Image:btn_dropdown_up.9.png btn_dropdown_up.9.png

Image:btn_dropdown_up_down.9.png btn_dropdown_up_down.9.png


To replace them, I'd suggest starting with these graphics, and making your own. Much like the background graphics, they're Nine-Patch PNG files. The ones in the Jar are precompiled, so you'll need to add the border yourself. If you don't, these graphics will get stretched across the entire Spinner, rather than sitting on the right side, which is what you want them to do.

Figuring out how to set the Nine-Patch border for these files is a little tricky, so here's how you'll want to set it up to get it to draw on the right side of the Spinner:


Image:Spinner_Selector_Ninepatch_example_small.png


And here's a larger example. so you can see the border better:


Image:Spinner_Selector_Ninepatch_example_large.png


This border could easily be modified to display the selector on the left side of the Spinnner, or anywhere else that you please.

Once you have your new Selector graphics imported into your application's drawable folder, you need to set up an XML file for it, also in drawable. I've named mine myspinner_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<!-- DROPDOWN SHOWING-->
<item android:state_first="true"
android:state_dropdown_showing="true"
android:drawable="@drawable/btn_dropdown_down"
/>
<item android:state_middle="true"
android:state_dropdown_showing="true"
android:drawable="@drawable/btn_dropdown_up_down"
/>
<item android:state_last="true"
android:state_dropdown_showing="true"
android:drawable="@drawable/btn_dropdown_up"
/>
<item android:state_single="true"
android:state_dropdown_showing="true"
android:drawable="@drawable/btn_dropdown_neither_up_down"
/>

<!-- DROPDOWN NOT SHOWING-->

<item android:state_first="true"
android:state_dropdown_showing="false"
android:drawable="@drawable/btn_dropdown_right_only"
/>
<item android:state_middle="true"
android:state_dropdown_showing="false"
android:drawable="@drawable/btn_dropdown_left_right_collapsed"
/>
<item android:state_last="true"
android:state_dropdown_showing="false"
android:drawable="@drawable/btn_dropdown_left_only"
/>
<item android:state_single="true"
android:state_dropdown_showing="false"
android:drawable="@drawable/btn_dropdown_neither"
/>


</selector>

 

As you can see, the Spinner selector has a number of states. It responds to these states:

 

  • android:state_dropdown_showing: This will be true if the dropdown is showing
  • android:state_first: This will be true if the first item in the list is selected
  • android:state_middle: This will be true if any of the middle items are selected
  • android:state_last: This will be true if the last item in the list is selected
  • android:state_single: And this will be true if the list only contains one item


Each sensible combination of these states needs an image associated with it. There are 8 such combinations, shown above.

Now back to your layout XML file. You'll need to add this Selector drawable to your spinner. This is done with the android:spinnerSelector property:

<Spinner android:id="@+id/spinner_chemical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:spinnerSelector="@drawable/myspinner_selector"
android:background="@drawable/myspinner_background"/>

If you've done everything correctly, you should now have a completely custom Spinner. Here's mine:

Image:Spinner_Example_New.png

 

Note: This tutorial is based on android-sdk_m5-rc15_windows.

---

Comments - Add a Comment

Gaetan
Thanks a lot, it's very usefull and nice explained.

anhtuan
what a wonderful tutorial! I love you so much ^_^

cc
cwofw [url=http://www.fjwowfjf.cn]wfwfe[/url] wfwfe

namrata
I tried this option. I am not able to define android:drawSelectorOnTop & android:spinnerSelector. When i am trying this in xml file it gives error.

Ando
Thanks a lot!your tutorial is very very usefull for me. thank!!

niz
Thanks a lot for sharing, really appreciate!

sandeep
this tutorial is very helpful.. I'll be very thankful if you post a tutorial on how to display a drop down list on click of a button..

Bill
Thanks for the cool tutorial. I've written another tutorial that your readers may be interested in about using custom java objects as the data source for spinner controls. You can find that tutorial here: http://www.katr.com/article_android_spinner01.php

website flash chat software
Thanks for interesting articles shared here, I feel strongly about it and would love to learn more on this topic. If possible, as you gain some more knowledge about it, would you mind updating your blog with more information? I am sure; it is extremely helpful and beneficial to many of your readers.

student loan
This is great Android: Custom Spinners source..

Send mothers day flowers Denmark
Excellent stuff from you, man I’ve read your things before and you are just too awesome. I adore what you have got right here. You make it entertaining and you still manage to keep it smart. This is truly a great blog thanks for sharing…

flowers Indonesia
I am absolutely amazed at how terrific the stuff is on this site. I have saved this webpage and I truly intend on visiting the site in the upcoming days. Keep up the excellent work!

Dodge Trucks
Thanks for share this excellent information with us i’ll never forget this type of information and tells others about it! Thanks once again


BLOG

SOAP Client for OSX
Developing Native iOS Apps with the Force.com Mobile SDK
Application Development with Android
Moving the Cloud - HTML5 and CSS3 on Node.js
Private Cloudwashing No Innovation? Duh
Painless Mobile App Development Webinar
Fluid Mobile HTML5 Design and Development
Codesign: Re-Signing an IPA between Apple accounts
Developers First Look at Windows 8 Metro
Storing Data Offline with Salesforce Mobile SDK SmartStore
Using XMLHttpRequest2 in iOS 5 or Android OS 3 to download binary files using HTML5/Phonegap
oAuth 2.0 for Salesforce.com
Setting Up and Using DiffDog for Salesforce.com Deployment Validation
The day the cloud stood still. Lessons learned roundup
Its Not Broken. Youre Just Doing It Wrong.
iOS Enterprise MDM Configuration Capabilities
Some Thoughts on Gamification
Cloud to Cloud: Using AWS Simple Email Service from Force.com
Importing a Flex 3 AIR project into Flash Builder 4
OSX Firefox Flex/Flash redraw bug workaround
Setting up automated testing in Flex SDK 3.3.0
Force.com Flex Toolkit AIRConnection updates
Clang! Powerful Memory Profiling for the iPhone
iPhone Programming: Adding a Contact to the iPhone Address Book
Lessons for the Beginning iPhone Developer
Installing a Whole-House Powered Humidifier without a Sail Switch
Eclipse IDE Irritations
Review: Zoom H4 Digital Audio Recorder
Android: Custom Spinners
Android: Custom Buttons
Android: Common Tasks
MP3 Encoding, 16 bit , 24 bit, or 32 bit?
Flash: A better sortOn() function
Rendering Isometric Tiles in Blender 3D
PHP: Replace "Smart Quotes" and other high-bit characters
Actionscript 3: Extra Timer Callback Parameters
OSC between Max/MSP and SC3
SC3: Flash and OSC
SC3 Tank Reverb (JMC)
Search SC3 Code Script
JPEG to WAV Converter
SC3 808 Kick Drum
SC3 Markov Chain
SC3 Pulse Train
Roland XP-80 Device XML for Cubase SX3