安卓SeekBar问题解决方案

14

在滑块被拖动时才移动进度条,这是否可能?当前情况是,即便在触摸进度绘制区域时,进度条也会移动。我们如何禁用在触摸进度绘制区域时进度条的移动?

谢谢。


1
你能解决这个问题吗?我也遇到了同样的问题,需要紧急帮助。 - Srikanth Pai
@Jay:嗨,我和你有同样的问题,你找到解决方案了吗?如果你有解决方案,请与我们分享... - Rishi
5个回答

9
我发现Ravi 的方案存在的问题是,触摸并移动到当前滑块位置之外仍会导致跳跃。
下面的类解决了这个问题,并用小增量(与箭头键相同)代替了触摸跳跃。
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);
    }
}

1
谢谢,这对我很有帮助。这看起来像是一个解决方案,而不是被接受的答案那样的暂时性解决方法。点赞+1。 - serine

6

覆盖OnTouchListener以处理滑动条上的移动事件,仅在MotionEvent为移动事件时处理拇指的移动。

event.getAction() == MotionEvent.ACTION_MOVE

更新:1

类似下面这样的代码可以工作,但问题是即使用户将拇指移动了2个单位,滑动条也会移动。你真的不应该停止这种行为,因为它会破坏滑动条。

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;
            }
        });

嗨,这对我有些有用...但是当我点击滑动条时,进度会增加而不需要移动或触摸拇指..你能给我详细的说明吗? - user1239418
听一下这里到底发生了什么...当我触摸滑动条时,它会自动进度而不需要触摸或移动拇指...我只想在我触摸并移动拇指时才进行进度。 - user1239418
这里检查条件n,然后返回true。 - user1239418
1
如果我只是触摸SeekBar而没有移动拇指,它会检测到MotionEvent.. 这是错误的。 - user1239418

3
这里是awy答案的Kotlin版本,唯一的区别是在你点击可绘制区域外部时不会发生任何移动。整个目的在于防止用户跳过。
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)
    }
}

1

Ravi的解决方案很好,我进行了一些重构:

两个目的:

  1. 解决getThumb()函数只能在API 16以上使用的问题。
  2. 点击seekbar不会触发onStopTrackingTouch(),而只是拖动滑块。

这是我的代码:

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);
    }
}

0

嗨,我不想让拇指消失,我只想禁用事件捕获...用户无法触摸到进度条并增加进度。只有当我移动拇指时,进度才能增加。谢谢。 - user1239418
现在发生了什么?当我点击滑动条的任何区域时,没有触摸并移动到拇指,拇指会自动移动,这对我来说是错误的...用户只能通过触摸和移动拇指来进行进度。 - user1239418

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接