Android SeekBar preference

Attention: This version of the SeekBar is obsolete, check out the new version instead

While working on my Android implementation of the Dislexicon, I realized I would need a SeekBar preference to adjust the text-to-speech speed. I found a couple of SeekBar prefs online, but none of them fit my needs. Specifically, I wanted it to:

  1. Appear on the main preference screen, instead of a separate window accessed via a button
  2. Fill the entire width of the screen
  3. Allow a minimum value other than zero

Here’s what I ended up with, as it appears in Dislexicon:

SeekBar Preference

You’ll need two files, plus a preferences section. They are all inline below, but you can download them here:

File Description
preferences.xml Example of adding a config to your preferences. The java class.
seek_bar_preference.xml The XML layout of the preference. This should go in your res/layout directory.


Here’s an example of configuring it in your preferences.xml file. Most of the parameters work exactly the same as a standard preference, but there are two new parameters:

  1. min: Minimum value to use for the slider. The default is zero
  2. units: The characters to put to the right of the value, to indicate the units (eg. %, deg, .oz)

[cc lang=”xml”]


The java class itself.
[cc lang=”java”]
package com.robobunny;

import android.content.Context;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

public class SeekBarPreference extends Preference implements OnSeekBarChangeListener {

private final String TAG = getClass().getName();

private static final String ANDROIDNS=””;
private static final String ROBOBUNNYNS=””;
private static final int DEFAULT_VALUE = 50;

private int mMaxValue = 100;
private int mMinValue = 0;
private int mInterval = 1;
private int mCurrentValue;
private String mUnitsLeft = “”;
private String mUnitsRight = “”;
private SeekBar mSeekBar;

private TextView mStatusText;

public SeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initPreference(context, attrs);

public SeekBarPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initPreference(context, attrs);

private void initPreference(Context context, AttributeSet attrs) {
mSeekBar = new SeekBar(context, attrs);
mSeekBar.setMax(mMaxValue – mMinValue);

private void setValuesFromXml(AttributeSet attrs) {
mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, “max”, 100);
mMinValue = attrs.getAttributeIntValue(ROBOBUNNYNS, “min”, 0);

mUnitsLeft = getAttributeStringValue(attrs, ROBOBUNNYNS, “unitsLeft”, “”);
String units = getAttributeStringValue(attrs, ROBOBUNNYNS, “units”, “”);
mUnitsRight = getAttributeStringValue(attrs, ROBOBUNNYNS, “unitsRight”, units);

try {
String newInterval = attrs.getAttributeValue(ROBOBUNNYNS, “interval”);
if(newInterval != null)
mInterval = Integer.parseInt(newInterval);
catch(Exception e) {
Log.e(TAG, “Invalid interval value”, e);


private String getAttributeStringValue(AttributeSet attrs, String namespace, String name, String defaultValue) {
String value = attrs.getAttributeValue(namespace, name);
if(value == null)
value = defaultValue;

return value;

protected View onCreateView(ViewGroup parent){

RelativeLayout layout = null;

try {
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

layout = (RelativeLayout)mInflater.inflate(R.layout.seek_bar_preference, parent, false);
catch(Exception e)
Log.e(TAG, “Error creating seek bar preference”, e);

return layout;


public void onBindView(View view) {

// move our seekbar to the new view we’ve been given
ViewParent oldContainer = mSeekBar.getParent();
ViewGroup newContainer = (ViewGroup) view.findViewById(;

if (oldContainer != newContainer) {
// remove the seekbar from the old view
if (oldContainer != null) {
((ViewGroup) oldContainer).removeView(mSeekBar);
// remove the existing seekbar (there may not be one) and add ours
newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
catch(Exception ex) {
Log.e(TAG, “Error binding view: ” + ex.toString());


* Update a SeekBarPreference view with our current state
* @param view
protected void updateView(View view) {

try {
RelativeLayout layout = (RelativeLayout)view;

mStatusText = (TextView)layout.findViewById(;

mSeekBar.setProgress(mCurrentValue – mMinValue);

TextView unitsRight = (TextView)layout.findViewById(;

TextView unitsLeft = (TextView)layout.findViewById(;

catch(Exception e) {
Log.e(TAG, “Error updating seek bar preference”, e);


public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newValue = progress + mMinValue;

if(newValue > mMaxValue)
newValue = mMaxValue;
else if(newValue < mMinValue) newValue = mMinValue; else if(mInterval != 1 && newValue % mInterval != 0) newValue = Math.round(((float)newValue)/mInterval)*mInterval; // change rejected, revert to the previous value if(!callChangeListener(newValue)){ seekBar.setProgress(mCurrentValue - mMinValue); return; } // change accepted, store it mCurrentValue = newValue; mStatusText.setText(String.valueOf(newValue)); persistInt(newValue); } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) { notifyChanged(); } @Override protected Object onGetDefaultValue(TypedArray ta, int index){ int defaultValue = ta.getInt(index, DEFAULT_VALUE); return defaultValue; } @Override protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { if(restoreValue) { mCurrentValue = getPersistedInt(mCurrentValue); } else { int temp = 0; try { temp = (Integer)defaultValue; } catch(Exception ex) { Log.e(TAG, "Invalid default value: " + defaultValue.toString()); } persistInt(temp); mCurrentValue = temp; } } } [/cc] The preference layout file. You can use this to tweek what the preference looks like. seek_bar_preference.xml
[cc lang=”xml”]



  1. Pierre Hébert

    Great work ! Very nice and useful.
    However I noticed that calling ‘notifyChanged();’ in ‘onProgressChanged’ prevents the proper tracking of the thumb. I suggest to update mStatusText only in ‘onProgressChanged’, and to actually change the preference value in ‘onStopTrackingTouch’. This will fix the tracking problem, and also will be a bit more efficient.

    • Kirk Baucom

      Thanks for the suggestion! I’ve updated the code.

  2. FulvioC

    FYI, setting a min value doesn’t seem to work. I have a value I want to go from 32 to 255 and the slider position moves incorrectly/erratically.

    • Kirk Baucom

      You’re right, there was a bug in the java code. The code that set the initial progress bar position was wrong, so the first time you moved it you’d get a seemingly random new value. I didn’t notice it because my min value was 1. I’ve updated the code. Thanks for the bug report, I hope the code is useful for you!

      • FulvioC

        Kirk, glad you got it fixed. And yes, it’s very useful!

  3. Ginger

    There are bug in this control when number of seekbars is more than one on single preference activity screen. Can your fix it?

    • Kirk Baucom

      It’s fixed now. I wasn’t handling the onBindView call correctly, so the views were getting switched around. I’ve tried to follow the method used by the built-in EditTextPreference, so hopefully it will behave itself. I made a couple of other small tweaks to make it work in a more “standard” fashion.

  4. Stella

    Thank you very much. it’s very useful.
    However, I don’t know what should I do tracking of the thumb using dpad(left-right).
    Could you inform to me?

    • Kirk Baucom

      I assumed you could just listen for them on the preference, but something seems to be grabbing keystrokes before they get there. I’ll post an update if I figure out how to do it.

      • Rui

        I’m also trying to control the progress bar with dpad (left-right). I already changed to add an OnKeyListener but onKey callback is not called!

        Any clue?!?

        BTW, thanks.. useful plugin

  5. vvkyc55

    Great! thank you very much. it’s good.

    • Kirk Baucom


  6. Jakub

    I am not sure if it works, cause if I use sharedpreferance with the same key in another place in my application it does not give value set within PreferanceActivity. Also if I set value outside PreferanceActivity with shared rpeference editor it doesn’t change value within SeekBarPreference.

    • Kirk Baucom

      Hmm, I’m not sure why that would be. I’m fetching the value in my app without any problems, but I’m not setting it outside the PreferenceActivity. Let me know if you find the issue.

  7. Ivan

    Thanks a lot for sharing you class!

  8. Jack Welch

    Thanks for writing this up in such detail — I learned a lot from it. I made a similar SeekBar in one of my projects and found that it ran fine in the android virtual device launched from Eclipse, but when I actually ran it on my phone, the app would crash as soon as I pressed the menu item that started up the Preferences screen. I fixed this issue by inverting the order of two lines in the initPreference method of the SeekBarPreference class. Here’s the order that worked for me:

    mSeekBar.setMax(mMaxValue – mMinValue);

    • Kirk Baucom

      Thanks for the info! I haven’t seen that happen, but it probably depends on what your listener is doing. I’ve swapped the order as you suggested, since it should be safer.

  9. JS

    Found two issues with this great code, thank you for that btw…

    I’m using this in a preference activity, and in the androidmanifest.xml I declare a theme for the preference activity . This causes the seek bar to not display. Anyone else encounter this?

    Also, another issue is the text and summary are not matching the default device theme colors, would be nice to have.

    Thanks again!

    • JS

      activity android:theme=”@android:style/Theme.Dialog

      – Sorry that got culled out I guess, had to remove the opening less-than sign.

    • Antoine

      Hi, this is a little old but have you find a way to solve that problem ? I have the same and i don’t know how to do.
      Thank you

  10. Egidijus

    I have some kind problems with the seek bar, when touch on thumb to change value it disappears, when I release my finger it appears….
    Also seek bar is “GONE”, when I have more then one element in preference category..
    How to solve this?

  11. Tobias

    Excellent code!
    I found it while trying to get rid of my Lint Warnings for “unused” custom attributes.
    Fell into a nasty little trap with the namespace because of an article on recommending
    xmlns:app="" as a namespace in Java file and corresponding XML file, which results in an immediately crash. While xmlns:app="http://com.mycompany.projectname" works fine.
    Any ideas how this namespace tying Java code and XML stuff together really works?


  12. shane

    I find this code doesn’t work well in diffirent version of Android. If works well in 2.3 and 4.0, But for 2.2.2 and 3.0 it doesn’t work well. How to solve this?

    • Kirk Baucom

      What behavior are you seeing?

      • shane

        The padding is not same as CheckBoxPreference and other exists Preference. I think the style maybe not right. But I can’t find how to solve this.

  13. Joost

    How to coop with an ‘android:dependancy’? The title stays white, althought the rest of the custom vies turns grey.

    • Kirk Baucom

      There are definitely problems with theming. I don’t know enough about Android UI theming to tell what’s going wrong, and I don’t have an actual Android device to test with (I just developed on the emulator). I’ve seen it behave differently on different devices depending on the phone vendor’s modifications.

      If anyone can offer any tips, I’d appreciate it.

  14. Radu

    Hi Kirk,

    Very good job on your Android tweak.
    What I would like to point out to Android experts is that, some of us are not familiar with Android.
    So, very clear “how to insert code” tutorials would be good. If you have the time, ofc.

    • Radu

      However, the code worked beautifully for me. Even thou I do not understand everything in it!

  15. toing

    nice tutorials, do you tell me how to build android application game tank step by step please, now i’m last semester in my study.please help me.

  16. chlek

    Hi Kirk,

    I’m trying to use your seek bar preference component on a very simple preference list app.

    The seek bar appears in a separate dialog Box and the value is never taken into account in the shared preference file… What am i doing wrong ??

    It seems impossible to debug the component either, i put a breakpoint in every single method and execution never stops (i’m using an emulator).

    i had a compilation problem also due to the Override key words that were placed before the overridden interface methods…

    Thanks in advance

  17. Qi Zhenyu

    Really a very good work, very valuable, improved a lot avoid to using the arrays.

  18. NatureTM

    Very useful. Thanks!

  19. Brian

    Thanks so much for doing this but I am having some issue getting the SeekBar to show up. I can see the title, summary and value text but no seekbar. Is there something obvious I might be missing?


    • Kirk Baucom

      I’m not sure what would cause that. Are you getting any errors in your log? The seek bar gets added to the view on line 106 of The first thing I’d try is setting a breakpoint there and stepping through to see if something is going wrong.

      • Brian

        Yeah it’s definitely hitting it, and no, no errors. I tried adding it to a framelayout instead, but nothing. HierarchyViewer is not showing any views below the LinearLayout container (nor the Framelayout when I tried that).

        Have you tried this with a PreferenceFragment? I’m just trying to figure out what I might be missing.

        • Brian

          Oh it works with a PreferenceActivity…that’s weird.

  20. Dieter Ladenhauf

    Good work and thanks for sharing. However, if the seekbar preference is disabled, its value can still be changed. To prevent this form happening, simply override setEnabled() in

    public void setEnabled(boolean enabled) {

    Best regards,

    • Vouskopes

      Thx, that worked!

  21. Aquero

    Great work…Thanks a lot for sharing.:). Is the attached code contains all the bugfixes and improvements made by you. If not, where can I find the latest code.

  22. majid

    why do i have to create a class for seekbar , i do not understand why can’t i just get the value
    i need a full tutorial about this . and this is my question . i hope someone can answer

  23. Frank

    This looks really cool, but after an hour or so of trying to compile it, I can’t figure out one line. In the preferences.xml, the 2nd line below for SeekBarPreference:

    Always fails with ‘error: Error parsing XML: unbound prefix’. Changing it to match my project name (like ) doesn’t fix it. I’ve tried many variations (and project cleans in-between), without success such as:

    Other than the 3 files, is there some additional project modifications necessary? I'd prefer not to have to name the project robobunny! Any suggestions would be appreciated, as I’d love to make this work.

    • Kirk Baucom

      There’s another name that needs to match between the code and the XML: the xmlns. I think that might be the problem you’re seeing.

      The line in the XML that reads xmlns:robobunny=”” must match the string in the code:
      private static final String ROBOBUNNYNS=””;
      (Obviously you can rename ROBOBUNNYNS if you do so throughout the code). Also, if you rename xmlns:robobunny to something else, you’ll need to also rename all the robobunny: strings in the XML. I think that’s probably what is wrong in your case from the error you’re getting.

      Let me know if that doesn’t fix your problem.

  24. Justin

    When using the android:dependency field the only thing that gets greyed out is the summary. The Seekbar is also still useable.

    • Justin

      Add this and your seekbars will respond to android:dependency:

      public void onDependencyChanged(Preference dependency, boolean disableDependent)
      super.onDependencyChanged(dependency, disableDependent);

      // /see if it has been initialized
      if (this.layout != null)

      • Justin

        Also add this in the onBindView(View view) method above updateView(View) to disable the seekbar when it first loads, otherwise you have to toggle the denpendency

        if(!this.layout.isEnabled() && this.layout != null){

      • ttkttk

        Hi, the “this.layout” gives me an error, how can i work this out? thx

        • Newt


          Thanks for the modifications they work perfectly.

          I have however done the code a little different and this may help you ttkttk:

          The on dependency changed
          public void onDependencyChanged(Preference dependency, boolean disableDependent) {
          super.onDependencyChanged(dependency, disableDependent);

          //Disable movement of seek bar when dependency is false
          if (mSeekBar != null)

          And the on bind view method:

          //if dependency is false from the beginning, disable the seek bar
          if (view != null && !view.isEnabled())


          Hope this helps you

  25. Kuitsi

    Thanks. I added it to bitbeaker. I had one problem when I tried to keep this class in it’s current package but I got it resolved by importing our package’s R class into

    • Kuitsi

      I had one other problem: summary was overlapping with seekBarPrefValue. I ended up adding android:layout_toLeftOf="@+id/seekBarPrefUnitsLeft" to summary. I had to include + sign before id or otherwise it just gave Error: No resource found that matches the given name. I have Android 2.3.6.

      • Newt


        Thanks for this post, I had the same problem. Seems to occur if the summary is a bit longer than expected. The Error that you are talking about is explained here just for future reference.

        I do have a slight problem with this method though. For some reason, once I made this change, the unitsRight text is now on the left of the value :?. Anybody know why this could be the case?

        • Newt

          I cannot explain this, but this is what I add to do completely to the layout file to fix the problem that I was having.

          Here is the layout of the file below title and above unitsLeft:

  26. Ted

    You didn’t have a license on your work. Is it alright to use this in a commercial android application?

    • Kirk Baucom

      Yes, you can consider it public domain. If you find any bugs or make any improvements, I’d appreciate it if you post them here.

  27. zliang

    Thanks much for sharing, Kirk,

    With your permission, Google should include this in the next Android release, as it’s very useful indeed.

  28. andrew moore

    I’m using your great seekbar in one of my apps.

    Instead of creating the layout from XML for the preferences page I’m creating the page dynamically in code as it’s quite variable.

    One issue I’ve come across is I’m not sure how to create a new instance of the seek bar with the AttributeSet attrs value. If using XML this gets automatically set. If I do it programatically how to I create it. If I just use the context – by changing the class a little, it mostly works, but then I get the indentation issue that I know you’ve referenced before here:

    What’s the best way I can use it in combination with dynamic screen creation?

    • Kirk Baucom

      I apologize that I can’t help you much, I don’t have very much experience with android GUI stuff myself. I created this widget for a program I was working on, but I haven’t used the built in android UI stuff subsequently. Hopefully someone else can answer your question.

      BTW, the guy posting in the thread you referenced was not me, his post was just worded slightly confusingly. He seems to have a widget based on mine, he may be able to assist you.

  29. Marvos

    Great piece of code, helped me a lot!

    I want to ask one thing, though. How would I dynamically set the minimum value of a seekbar to be equal to the current value of another seekbar? Think Max speed / Min speed values, the min value should not be able to go above the max one.

    • Marvos

      “the min value should not be able to go above the max one.”

      wrong words there, the max value should not be able to go below the min one 🙂

    • Kirk Baucom

      You’d have to add a couple new parameters to that can be updated externally, then check those new values in onProgressChanged to see if the user tried to make the setting lower or higher than is allowed. You can just return without setting anything (like the code in the middle of onProgressChanged). You’d also have to update the setting on the bar when something changes the min or max value. Then of course you’d have to have the two seekbars send updates back and forth.

      It gets very tricky when you’re trying to link two bar settings together like that, especially for the user. The ideal solution would be to have two handles on one bar, so it’s obvious to the user what is going on when the handles won’t cross each other. You can also have one handle slide the other when they bump, or hit a minimum distance from each other. Many years ago I used something like that in a game for a bar used to allocate energy, and it worked out ok. That might actually be easier to do than making two seek bars talk to each other, too.

  30. michael evanov

    Thank you very much.

  31. Archie

    Dude ur the best! This is exactly where I got stuck.

  32. voelklflo

    Thanks for sharing your code. This is a big help for me.
    I added another ‘android:layout_toLeftOf=”@+id/seekBarPrefUnitsLeft”‘ to the summary-block in seek_bar_preference.xml. This way long summaries don’t overlap the prefUnit-stuff.

  33. Yair

    Hi Kirk,
    I’ve used your preference and it’s excellent. However, I had one problem with it – it doesn’t use the theme, so it looks completely different than the other preferences on my activity.
    So – I’ve changed it abit, basically so it will use the default Preference’s layout, and your layout deals only with the widgetFrame in it.
    If you would like – I can send you the changes I’ve done.


  34. n0iz

    Hi Kirk,
    nice work!

    But i’ve had some troubles while using your implementation on Android 4.2. with PreferenceFragments, so i decided to build my own one from scratch;)
    My implementation is based on the CheckButtonPreference and is reusing the base Android stuff, i just extend Androids default layout, so it should look like the Version of Android you are using.
    And it’s a Library Project btw.

    Feel free to check it out, the source is available on github.


  35. Patrick

    Thanks for the code 🙂 I made a few changes to accept attribute values from resources (for example robobunny:min=”@integer/my_min_value”) I added this method:

    private int getAttributeInt (Context context, AttributeSet attrs,
    String name, int defaultValue)
    int resource = attrs.getAttributeResourceValue (NAMESPACE, name, 0);
    return (resource == 0) ? attrs.getAttributeIntValue (NAMESPACE, name,
    defaultValue) : context.getResources ().getInteger (resource);

  36. Kamal

    Hii Kirk,

    I am working on a TEXT TO SPEECH (TTS) app development which read a text file, with varying voice speed and voice pitch.

    please suggest me how to use these two function on a two different seekbars :

    public int setPitch (float pitch) and public int setSpeechRate (float speechRate)

    Also currently I am reading from a string, instead of this I want to read from a text file.

    Please reply ASAP.

    Thanks in advance 🙂

    • Soren

      I added a divisor as one of the fields and created a mDivisor in the code, and then added this code

      if (mDivisor > 1) {
      mStatusText.setText(new DecimalFormat("0.0##").format((float)mCurrentValue / (float)mDivisor));
      } else {

      in place of the existing setText at the two proper locations. upper and lower limits need to be multiplied by the divisor.

      Good luck.

  37. Rob

    That works well. Thanks for posting …

    • Rob

      Just one thing i had to do was to use the fromUser variable in onProgressChanged to set the initial value

  38. Newt


    This preference component looks amazing! 🙂
    But I am having a problem :(.

    The SeekBarPreference is only displaying the seek bar and the title. I don’t see a summary or actual value or “unitsRight” either.

    Does anyone know what the problem could be? I have copied the code and everything exactly, and it’s not working :/. I am running this on min API 14, if that maybe has something to do with the problem.

    • Newt

      I think I found my problem:

      I did not realise that this was white :O, once removed, I could see everything :).

      Thanks for the preference component robobunny! 🙂

  39. Aleks

    Great work, thank you so much! I made a couple of improvements (in my view) and encountered one issue. First, in the XML for the preference, I removed the font specifics for the title and instead added style="@android:style/TextAppearance.Large" – this automatically takes care of displaying the correct font for corresponding versions of android. Second, I added showValue attribute, which can be true/false – when set to “false”, the value currently selected on the seek bar is not displayed in the mStatusText (I needed this for my specific case).

    Now, the issue that I encountered. I have the seekbar set with min=0, max=91, interval=7 (to select from 0 to 13 weeks in 1 week interval – but get results in days). When I touch and slide, the seekbar adjusts once to the next step value (up or down) and then stops. I have to remove my finger, then touch again and slide again to continue adjustment. I don’t think this is the right behaviour though. What am I missing here?

    • Aleks

      Ok, on further investigation the issue seems to be caused by updates to ANY preference in the onPreferenceChangeListener of the SeekBarPreference. In my case, when the seekbar position changes, in my listener I am updating summary and enable/disable status of another preference just below this one. If I comment out this update code, then everything works as expected. Any ideas as to how to fix it?

      • Newt

        I can’t think of any reason why this would be happening. It doesn’t make much sense. When moving the seek bar it should continue to move between intervals, that is my guess. This is very strange. Could you please help me out Aleks, does your SeekBarPreference saw everything that is shown in the picture at the top? For some reason, mine is only showing “Speech Speed”, it only appears to show the title. The summary, unitsLeft, and unitsRight are not visible 😐

        • Newt

          I have found some code that may be useful to you Aleks:

          public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) {
          mCurrentValue = value + mMinValue;

          I found this here.

          I don’t know what you changed, but I think this might be worth looking at.

  40. Timo

    Thanks! Works just great!


  41. bugaa92

    How can I create a new object of type SeekBarPreference and your constructors? I do not know what values should I give to context and attributes.

  42. tap sports baseball hack free cash

    Howdy just wanted to give you a quick heads up and let you know a few
    of the images aren’t loading correctly. I’m not sure why but I think its a linking issue.
    I’ve tried it in two different web browsers and both show the same

  43. NemoDo

    Thanks for your source, but when i set icon for this preference, icon and title are in different line. How to set them in one line like others

Leave a Reply

Your email address will not be published.

© 2024

Theme by Anders NorenUp ↑