即使没有进度改变,onProgressChanged也会运行

时间:2016-03-04 10:17:40

标签: java android seekbar android-seekbar android-vertical-seekbar

我有一个带有两个搜索栏的Android应用程序,我已将它们设置为使应用程序不响应,除非它们都被按下。我的问题是,当它们都被按下时,方法onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)开始在无限循环中连续运行。即使我将手指完全放在条形上,也会发生这种情况(这意味着任何条形图上的进度都没有变化,因此不应该调用onProgressChanged方法)。有没有人对为什么会发生这种情况有任何见解?

以下是一些相关代码:

void setupLRSpeedBars(final int UIID, final Bool bar1, final Bool bar2) {
    SeekBar sb = (SeekBar) findViewById(UIID);
    sb.setProgress(9);
    sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (bar1.isTrue()) {
                progress -= 9;
                transmit((UIID == R.id.leftSpeedBar ? "L" : "R") +
                         (progress >= 0 ? "+" : "") +
                          Integer.toString(progress));
            }
        }

        public void onStartTrackingTouch(SeekBar seekBar) {
            bar2.set(true);
        }

        public void onStopTrackingTouch(SeekBar seekBar) {
            bar2.set(false);
            seekBar.setProgress(9);
            //transmit((UIID == R.id.leftSpeedBar ? "L" : "R") + "+0");
            transmit("s");
        }
    });
}

另请注意,我使用了自定义Bool类而不是原始boolean,以便让我绕过限制OnSeekBarChangeListener之外的所有变量final。 (我需要在onSeekBarChangeListeners之间发送信息,以便确定用户是否同时按住两个搜索栏) 我有预感,这可能是我的问题的原因,但我不知道如何。

class Bool {
    private boolean bool;
    public Bool () {}
    public Bool(boolean bool) { this.bool = bool; }
    public void set (boolean bool) { this.bool = bool; }
    public boolean get () { return bool; }
    public boolean isTrue () { return bool; }
}

编辑: 我还会注意到我正在使用自定义的垂直搜索栏。这是代码:

package android.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class VerticalSeekBar extends SeekBar {

    private OnSeekBarChangeListener myListener;
    public VerticalSeekBar(Context context) {
        super(context);
    }

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

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

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    @Override
    public void setOnSeekBarChangeListener(OnSeekBarChangeListener mListener){
        this.myListener = mListener;
    }

    @Override
    public synchronized void setProgress(int progress){
        super.setProgress(progress);
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }

    protected void onDraw(Canvas c) {
        c.rotate(-90);
        c.translate(-getHeight(), 0);

        super.onDraw(c);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if(myListener!=null)
                    myListener.onStartTrackingTouch(this);
                break;
            case MotionEvent.ACTION_MOVE:
                setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                myListener.onProgressChanged(this, getMax() - (int) (getMax() * event.getY() / getHeight()), true);
                break;
            case MotionEvent.ACTION_UP:
                myListener.onStopTrackingTouch(this);
                break;

            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return true;
    }
}

1 个答案:

答案 0 :(得分:2)

我认为问题出在您onTouchEvent的{​​{1}}实施中,因为您正在处理收到的每个VerticalSeekBar

来自the documentation

  

每当当前触摸接触位置,压力或大小发生变化时,都会通过ACTION_MOVE事件触发新的onTouchEvent()。如检测常见手势中所述,所有这些事件都记录在onTouchEvent()的MotionEvent参数中。

     

因为基于手指的触摸并不总是最精确的交互形式,所以检测触摸事件通常更多地基于移动而不是简单接触。为了帮助应用程序区分基于移动的手势(例如滑动)和非移动手势(例如单击),Android包含了触摸slop的概念。"触摸斜率是指在将手势解释为基于移动的手势之前用户的触摸可以以像素为单位的距离。有关此主题的更多讨论,请参阅在ViewGroup中管理触摸事件。

也就是说,您认为您的手指完全静止但您的搜索栏正在接收MotionEvent.ACTION_MOVE个事件。

在你的情况下,"触摸slop"近似现在是一个好主意,因为计算出的触摸斜率对于您的目的而言非常大,如touch slop is defined as

  

"触摸slop" “手指”是指在手势被解释为滚动之前用户的触摸可以以像素为单位的距离。 Touch slop通常用于防止在用户执行某些其他触摸操作时意外滚动,例如触摸屏幕元素。

要解决您的问题,您可以计算最后一个管理位置与当前管理位置之间的距离,以触发ACTION_MOVE

onProgressChanged
相关问题