Skip to content

Instantly share code, notes, and snippets.

@mobiRic
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mobiRic/c65a57a2a52c7f48f3db to your computer and use it in GitHub Desktop.
Save mobiRic/c65a57a2a52c7f48f3db to your computer and use it in GitHub Desktop.
Custom Android SeekBar that allows for easy increment / decrement by touch.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- CUSTOM SEEKBAR -->
<declare-styleable name="NoSkipSeekBar">
<attr name="keyProgressIncrement" format="integer" />
</declare-styleable>
</resources>
<lib.widget.NoSkipSeekBar
android:id="@+id/seekBarPercent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:keyProgressIncrement="10" />
package lib.widget;
import mobi.glowworm.example.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.SeekBar;
/**
* NoSkipSeekBar is an extension of {@link SeekBar} that prevents jumps in position by touching
* outside the current thumb position. </p>
*
* Touches are replaced by an increment or decrement the same as would be achieved using a DPAD's
* Left or Right arrow keys. The amount to increment can be defined in XML using the custom
* <code>keyProgressIncrement</code> tag, or in code using {@link #setKeyProgressIncrement(int)}.
*/
public class NoSkipSeekBar extends SeekBar
{
/**
* <code>true</code> if the thumb is being dragged; <code>false</code> otherwise.
*/
private boolean isDragging;
public NoSkipSeekBar(Context context)
{
super(context);
}
public NoSkipSeekBar(Context context, AttributeSet attrs)
{
super(context, attrs);
if (!isInEditMode())
{
initXml(context, attrs);
}
}
public NoSkipSeekBar(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
if (!isInEditMode())
{
initXml(context, attrs);
}
}
private void initXml(Context context, AttributeSet attrs)
{
TypedArray a =
context.getTheme().obtainStyledAttributes(attrs, R.styleable.NoSkipSeekBar, 0, 0);
try
{
int keyProgressIncrement =
a.getInteger(R.styleable.NoSkipSeekBar_keyProgressIncrement, 1);
setKeyProgressIncrement(keyProgressIncrement);
}
finally
{
a.recycle();
}
}
/**
* Set the range of the progress bar to <code>0...max</code>. </p>
*
* Allows the key progress increment value to remain the same, or to be automatically updated as
* if {@link #setMax(int)} was used instead.
*/
public synchronized void setMax(int max, boolean autoUpdateKeyProgressIncrement)
{
int oldIncrement = getKeyProgressIncrement();
setMax(max);
if (!autoUpdateKeyProgressIncrement)
{
setKeyProgressIncrement(oldIncrement);
}
}
private boolean isWithinThumb(MotionEvent event)
{
return getThumb().getBounds().contains((int) event.getX(), (int) event.getY());
}
/**
* Increments or decrements the progress value, based on the sign of parameter.
*
* @param direction
* Set > 0 to increment; < 0 to decrement.
*/
private void increment(int direction)
{
if (direction != 0)
{
final KeyEvent key =
new KeyEvent(KeyEvent.ACTION_DOWN, (direction < 0 ? KeyEvent.KEYCODE_DPAD_LEFT
: KeyEvent.KEYCODE_DPAD_RIGHT));
onKeyDown(key.getKeyCode(), key);
}
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
if ((!isEnabled()) || (getThumb() == null))
{
return super.onTouchEvent(event);
}
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
if (!isWithinThumb(event))
{
return true;
}
isDragging = true;
break;
}
case MotionEvent.ACTION_UP:
{
if (!isDragging)
{
final Rect r = getThumb().getBounds();
increment((int) event.getX() - (r.left + r.right) / 2);
return true;
}
isDragging = false;
break;
}
case MotionEvent.ACTION_MOVE:
{
if (!isDragging)
{
return true;
}
break;
}
case MotionEvent.ACTION_CANCEL:
{
isDragging = false;
break;
}
}
return super.onTouchEvent(event);
}
}
@mobiRic
Copy link
Author

mobiRic commented Jun 26, 2014

NoSkipSeekBar is a custom Android android.widget.SeekBar that overrides the normal onTouch behaviour to prevent the thumb from skipping to the touched position. Instead, the thumb will increment or decrement by a set amount, as if the right or left arrow was pressed.

Originally copied from code by user @awy on a Stack Overflow answer at http://stackoverflow.com/a/20654485/383414

@mobiRic
Copy link
Author

mobiRic commented Jun 26, 2014

Updated formatting & code conventions.

@mobiRic
Copy link
Author

mobiRic commented Jun 26, 2014

Updated to allow touch increment to be set via XML using custom keyProgressIncrement tag in layout.

@mobiRic
Copy link
Author

mobiRic commented Jun 30, 2014

Fixed occasional false increment after dragging thumbnail.

@mobiRic
Copy link
Author

mobiRic commented Jun 30, 2014

Add setMax() overload to allow key progress increment to remain the same when max is updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment