Last active
August 29, 2015 14:03
-
-
Save mobiRic/c65a57a2a52c7f48f3db to your computer and use it in GitHub Desktop.
Custom Android SeekBar that allows for easy increment / decrement by touch.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<!-- CUSTOM SEEKBAR --> | |
<declare-styleable name="NoSkipSeekBar"> | |
<attr name="keyProgressIncrement" format="integer" /> | |
</declare-styleable> | |
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<lib.widget.NoSkipSeekBar | |
android:id="@+id/seekBarPercent" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
custom:keyProgressIncrement="10" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
Updated formatting & code conventions.
Updated to allow touch increment to be set via XML using custom keyProgressIncrement tag in layout.
Fixed occasional false increment after dragging thumbnail.
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
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