Android seekbar solution
Asked Answered
Z

5

14

Is it possible to have the seekbar move only when the thumb is moved. Right now the seekbar moves even on finger touch in the progressdrawable. How do we disable the movement of the seekbar on finger touch of the progressdrawable?

Thanks.

Zapata answered 20/3, 2012 at 13:38 Comment(2)
where you able to achieve this ? i am having the same problem urgent help neededTillio
@Jay : HI, i have same problem like you you found any solution for this ?? Please share with us if you have solution for this...Giselegisella
A
6

Override the OnTouchListener for the seekbar and only process the movement on the thumb when the MotionEvent is a move event.

event.getAction() == MotionEvent.ACTION_MOVE

Update : 1

Something like this will work but the catch is that even if the user moves the thumb 2 units the seekbar moves. And you should really not stop this behavior as it would mess the the seekbar.

seekBar.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction() == MotionEvent.ACTION_MOVE){
                    Log.d(TAG, "Moved , process data, Moved to :" + seekBar.getProgress());
                    seekBar.setProgress(seekBar.getProgress());
                    return false;
                }
                Log.d(TAG, "Touched , Progress :" + seekBar.getProgress());
                return true;
            }
        });
Alyosha answered 20/3, 2012 at 13:50 Comment(4)
Hie, its somehow useful for me.. but still when i am clicking on seekbar, progree is incresing without move or touch to thumb.. can u give me full detail please?Zapata
listen what exactly happening here.. when i touch on seekbar it progress automatically without touching or moving on thumb.. i just want to progress it within when i touch n move thumb..Zapata
here its check if condition n after that gone to return true alsoZapata
if i just touched on seekbar without moving thumb it detects motionevent.. it is wrong..Zapata
C
9

I found that the problem with Ravi's solution is that touching and moving outside of the current thumb position would still result in a jump.

The class below resolves that issue and replaces the jump-on-touch with a small increment, the same as one would get with arrow keys.


import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.SeekBar;

/**
 * A NoSkipSeekBar is an extension of {@link SeekBar} that prevents jumps in position
 * by touching outside the current thumb position. Such touches are replaced by
 * an increment or decrement the same as would be achieved using a DPAD's Left or
 * Right arrow keys.
 */
public class NoSkipSeekBar extends SeekBar {

    public NoSkipSeekBar(Context context) {
        super(context);
    }

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

    public NoSkipSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private boolean isDragging;

    private boolean isWithinThumb(MotionEvent event) {
        return getThumb().getBounds().contains((int)event.getX(), (int)event.getY());
    }

    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)) {
                isDragging = true;
                return super.onTouchEvent(event);
            } else {
                return true;
            }

        case MotionEvent.ACTION_UP:
            isDragging = false;
            if (isWithinThumb(event)) {
                return super.onTouchEvent(event);
            } else {
                final Rect r = getThumb().getBounds();
                increment((int)event.getX() - (r.left + r.right) / 2);
                return true;
            }

        case MotionEvent.ACTION_MOVE:
            if (!isDragging) return true;
            break;

        case MotionEvent.ACTION_CANCEL:
            isDragging = false;
            break;
        }

        return super.onTouchEvent(event);
    }
}
Colloidal answered 18/12, 2013 at 9:41 Comment(1)
thanks it helped me, this looks like a solution not a temporary workaround like the accepted answer, +1 for thatPentastich
A
6

Override the OnTouchListener for the seekbar and only process the movement on the thumb when the MotionEvent is a move event.

event.getAction() == MotionEvent.ACTION_MOVE

Update : 1

Something like this will work but the catch is that even if the user moves the thumb 2 units the seekbar moves. And you should really not stop this behavior as it would mess the the seekbar.

seekBar.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction() == MotionEvent.ACTION_MOVE){
                    Log.d(TAG, "Moved , process data, Moved to :" + seekBar.getProgress());
                    seekBar.setProgress(seekBar.getProgress());
                    return false;
                }
                Log.d(TAG, "Touched , Progress :" + seekBar.getProgress());
                return true;
            }
        });
Alyosha answered 20/3, 2012 at 13:50 Comment(4)
Hie, its somehow useful for me.. but still when i am clicking on seekbar, progree is incresing without move or touch to thumb.. can u give me full detail please?Zapata
listen what exactly happening here.. when i touch on seekbar it progress automatically without touching or moving on thumb.. i just want to progress it within when i touch n move thumb..Zapata
here its check if condition n after that gone to return true alsoZapata
if i just touched on seekbar without moving thumb it detects motionevent.. it is wrong..Zapata
J
3

Here's a Kotlin version of awy's answer with the caveat that absolutely no movement happens when you tap outside the drawable. The whole point is that you don't want users to be able to skip.

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatSeekBar

class NoSkipSeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : AppCompatSeekBar(context, attrs, defStyle) {

    private var isDragging = false

    private fun isWithinThumb(event: MotionEvent): Boolean {
        return thumb.bounds.contains(event.x.toInt(), event.y.toInt())
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (!isEnabled || thumb == null) return super.onTouchEvent(event)

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (isWithinThumb(event)) {
                    isDragging = true
                    return super.onTouchEvent(event)
                } else {
                    return true
                }
            }
            MotionEvent.ACTION_UP -> {
                isDragging = false

                return when {
                    isWithinThumb(event) -> super.onTouchEvent(event)
                    else -> true
                }
            }
            MotionEvent.ACTION_MOVE -> if (!isDragging) return true
            MotionEvent.ACTION_CANCEL -> isDragging = false
        }
        return super.onTouchEvent(event)
    }
}
Jugoslavia answered 3/6, 2020 at 4:12 Comment(0)
B
1

Ravi's solution is great, I did some refactoring below:

Two purposes:

  1. resolve the getThumb() function that only can use above the API 16 issues.
  2. clicking the seekbar will not invoke the onStopTrackingTouch() but only drag the thumb

This is my code:

public class NoSkipSeekBar extends SeekBar {

    Drawable mThumb;
    @Override
    public void setThumb(Drawable thumb) {
        super.setThumb(thumb);
        mThumb = thumb;
    }
    public Drawable getSeekBarThumb() {
        return mThumb;
    }

    public NoSkipSeekBar(Context context) {
        super(context);
    }

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

    public NoSkipSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private boolean isDragging;
    private boolean isStart = false;
    private boolean isWithinThumb(MotionEvent event) {
        Rect rect = getSeekBarThumb().getBounds();//increate the thumb invoke area
        Rect rect1 = new Rect();
        rect1.left = rect.left - 50;
        rect1.right = rect.right + 50;
        rect1.bottom = rect.bottom + 50;
        return rect1.contains((int)event.getX(), (int)event.getY());
    }

    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() || getSeekBarThumb() == null) return super.onTouchEvent(event);

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (isWithinThumb(event)) {
                    isDragging = true;
                    isStart = true;
                    return super.onTouchEvent(event);
                } else {
                    return true;
                }

            case MotionEvent.ACTION_UP:
                isDragging = false;
                if(isStart){
                    isStart = false;
                    return super.onTouchEvent(event);
                }
                if (isWithinThumb(event)) {
                    return super.onTouchEvent(event);
                } else {
                    //final Rect r = getThumb().getBounds();
                    //increment((int)event.getX() - (r.left + r.right) / 2);
                    return true;
                }
            case MotionEvent.ACTION_MOVE:
                if (!isDragging) return true;
                break;

            case MotionEvent.ACTION_CANCEL:
                isDragging = false;
                break;
        }

        return super.onTouchEvent(event);
    }
}
Babur answered 8/8, 2016 at 7:51 Comment(0)
T
0

Have you looked at this:

Really similar thread which should help you solve your question:

SeekBar's thumb only appears when touched

Best of luck

Tiphani answered 20/3, 2012 at 13:43 Comment(2)
Hi i dont want to disappear thumb, i just want to disable trapping event.. user can't able to touch on seekbar n increase progress. progress can be increase only when i move the thumb. ThanksZapata
Right now what happening? When i click on seekbar's region anywhere on it without touch n move to thumb, thumb will move automatically it is wrong with me..user can only progress with touch n move on thumb.Zapata

© 2022 - 2024 — McMap. All rights reserved.