12

I'm trying to make a SeekBar move more smoothly than just jumping straight to the position. I'm doing this as I've got a SeekBar with 3 options for a slider-type implementation.

I'm looking to create a nice smooth slider with 3 options "Yes", "No option", "No" for a feature in my app and a SeekBar looks the best and easiest way.

I've tried looking at Android Animation and it seems a tad bit complex, so if anyone could be of any help that would be nice :)

Joe Simpson
  • 2,546
  • 4
  • 30
  • 46

6 Answers6

15

I found the following solution to make the seekbar move smoothly, yet still snap to a limited range of values. Assuming you have the following views in your layout:

<SeekBar
  android:id="@+id/sldProgress"
  style="@style/MySliderStyle"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:max="100"
  android:progress="50" />

<TextView
  android:id="@+id/lblProgress"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="5" />

You can use the following code in your activity (change the value of android:max in the above xml, and the smoothness factor in the code below according to your needs - higher values = smoother):

public class MyActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    sliderListener sldListener = new sliderListener();
    SeekBar sldProgress = (SeekBar) findViewById(R.id.sldProgress);
    sldProgress.setOnSeekBarChangeListener(sldListener);
  }
  private class sliderListener implements OnSeekBarChangeListener {
    private int smoothnessFactor = 10;
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
      progress = Math.round(progress / smoothnessFactor);
      TextView lblProgress = (TextView) findViewById(R.id.lblProgress);
      lblProgress.setText(String.valueOf(progress));
    }

    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    public void onStopTrackingTouch(SeekBar seekBar) {
      seekBar.setProgress(Math.round((seekBar.getProgress() + (smoothnessFactor / 2)) / smoothnessFactor) * smoothnessFactor);
    }
  }
}
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
Russ
  • 3,768
  • 7
  • 28
  • 37
  • 5
    Whoever downvoted this, please explain what is wrong with the answer - remember, downvoting is only meant to be used in extreme cases where no effort went into the answer or the answer is dangerous. If the answer is dangerous I would like to know why! Thank you. – Russ Sep 10 '12 at 13:02
  • 1
    Integer.parseInt(String.valueOf(Math.round(progress / smoothnessFactor))); This doesn't seem right. progress/smoothnessFactor will always yield an int, so there's no need to round it, then you're just converting it to a string then back to an int. – theelfismike May 03 '13 at 20:43
  • 5
    Is that all? Hardly going to blow up your app is it? I have edited the code to remove those unnecessary conversions (anybody could have done that - no need to vote down). – Russ May 05 '13 at 07:13
  • 5
    Downvote if the answer is wrong, not if it can be corrected by a few lines of deletion. Bad downvoters are equally responsible to mess SO up. – Siddharth May 05 '13 at 07:30
  • 1
    @theelfismike Thanks at least for telling me what was wrong, but please take a look at the guidelines on downvoting: http://stackoverflow.com/privileges/vote-down – Russ May 05 '13 at 08:07
  • You don't need to define the max as 100, this is the default value. – worked Jan 03 '16 at 23:01
6

You don't need to build anything by yourself just user android animation it will do the thing for you

The code written in kotlin

    mySeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
            //Todo: code
        }

        override fun onStartTrackingTouch(seekBar: SeekBar?) {
        }

        override fun onStopTrackingTouch(seekBar: SeekBar) {
            if (seekBar.progress > 70) {
                ObjectAnimator.ofInt(seekBar, "progress", 100).setDuration(100).start()
            } else if (seekBar.progress < 30) {
                ObjectAnimator.ofInt(seekBar, "progress", 0).setDuration(100).start()
            } else {
                ObjectAnimator.ofInt(seekBar, "progress", 50).setDuration(100).start()
            }
        }
    })
Andrew Hossam
  • 381
  • 4
  • 12
4

Built my own control. Job done :) Code here

Siddharth
  • 9,349
  • 16
  • 86
  • 148
Joe Simpson
  • 2,546
  • 4
  • 30
  • 46
  • 1
    +1 You can add the source code so that you will help visitors in the future. – Eng.Fouad Mar 15 '12 at 22:07
  • I will, I'll post it as soon as I push the lastest version of my application. I think the app's open source anyway – Joe Simpson Mar 16 '12 at 08:58
  • 3
    As promised - https://github.com/kennydude/Speaker/blob/master/src/me/kennydude/speaker/SmoothSeekBar.java that location will be updated as code updates – Joe Simpson Mar 19 '12 at 14:52
2

Create a custom SeekBar

public class SmoothSeekBar extends AppCompatSeekBar implements SeekBar.OnSeekBarChangeListener {

private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;

private boolean mNeedCallListener = true;

private ValueAnimator mAnimator;

public SmoothSeekBar(Context context) {
    super(context);
    init(context);
}

public SmoothSeekBar(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public SmoothSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}


public void init(Context context) {
    Context mContext = context;
}

@Override
public void setOnSeekBarChangeListener(
        SeekBar.OnSeekBarChangeListener onSeekBarChangeListener) {
    mOnSeekBarChangeListener = onSeekBarChangeListener;
    super.setOnSeekBarChangeListener(this);
}

@Override
public void setProgress(final int progress) {
    final int currentProgress = getProgress();
    if (mAnimator != null) {
        mAnimator.cancel();
        mAnimator.removeAllUpdateListeners();
        mAnimator.removeAllListeners();
        mAnimator = null;
        mNeedCallListener = true;
    }
    mAnimator = ValueAnimator.ofInt(currentProgress, progress);
    mAnimator.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
    mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
    mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int value = (int) animation.getAnimatedValue();
            if (value == progress) {
                mNeedCallListener = true;
            } else {
                mNeedCallListener = false;
            }
            Logger.e("ProgressBar value ", value + "");
            SmoothSeekBar.super.setProgress(value);
        }
    });
    mAnimator.start();

}

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    if (fromUser || mNeedCallListener) {
        if (mOnSeekBarChangeListener != null) {
            mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
        }
    }
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
    if (mOnSeekBarChangeListener != null) {
        mOnSeekBarChangeListener.onStartTrackingTouch(seekBar);
    }
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
    if (mOnSeekBarChangeListener != null) {
        mOnSeekBarChangeListener.onStopTrackingTouch(seekBar);
    }
}
}

Now add SeekBar in xml and enjoy

 <com.yourPackage.SmoothSeekBar
    android:id="@+id/seekBar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
Ness Tyagi
  • 2,008
  • 24
  • 18
1

This works fine for me, quite simple and straight forward.

if (currentPosition > 0) {
    ObjectAnimator animation = ObjectAnimator.ofInt(seekBar, "progress", currentPosition);
    animation.setDuration(400);
    animation.setInterpolator(new DecelerateInterpolator());
    animation.start();
}
Mohammad Usman
  • 37,952
  • 20
  • 92
  • 95
user7023213
  • 3,460
  • 2
  • 11
  • 15
0

I made a custom view library for Smooth Seek Bar animation.

Try it!

https://github.com/WoochanLee/SmoothSeekBar

  • settings.gradle
dependencyResolutionManagement {
    ...
    repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}
  • build.gradle
dependencies {
    ...
    implementation 'com.github.WoochanLee:SmoothSeekBar:1.0.0'
}
  • in your xml
<com.woody.lee.library.smoothseekbar.SmoothSeekBar
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
Woochan Lee
  • 324
  • 2
  • 9