0

我有一个带有两个seekbars的android应用程序,并且我已经设置了它们以便应用程序不响应,除非它们都被按下。我的问题是,当它们都被按下时,方法onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)开始在无限循环中持续运行。即使我将手指完全握在条上(这意味着任一条上的进度都不会发生变化,因此不应调用onProgressChanged方法),但这种情况发生。有没有人有任何见解,为什么会发生这种情况?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; 
    } 
} 
+0

sb.setProgress(9);会触发它onChangeListener –

+0

@SanketKachhela是的,但是这个调用在应用程序开始时只发生一次,而不是在无限循环中发生1000次。另外它发生在我设置了自定义的OnSeekBarChangeListener之前 – TheIronKnuckle

回答

2

我认为这个问题是在执行onTouchEventVerticalSeekBar,因为你正在处理每MotionEvent.ACTION_MOVE接收。

the documentation

一个新的onTouchEvent()被触发与ACTION_MOVE事件每当当前触摸接触位置,压力,或尺寸的变化。如检测常见手势中所述,所有这些事件都记录在onTouchEvent()的MotionEvent参数中。因为基于手指的触摸并不总是最精确的交互形式,所以检测触摸事件通常更多地基于移动而不是简单的接触。为了帮助应用程序区分基于移动的手势(例如滑动手势)和非移动手势(如单击),Android包含“触摸斜倚”的概念。触摸斜率指的是在手势被解释为基于移动的手势之前用户的触摸可以漫游的像素距离。有关此主题的更多讨论,请参阅管理ViewGroup中的触摸事件。

也就是说,你认为你的手指完全静止但你的搜索栏正在接受ACTION_MOVE事件。

在你的情况下,“触摸污”近似现在是一个好主意,因为计算的触摸斜率是巨大的你的目的,为touch slop is defined as

“触摸坡”是指像素的距离用户的触摸可以在手势被解释为滚动之前漫游。触摸坡度通常用于防止用户在执行其他触摸操作(例如触摸屏幕元素)时发生意外滚动。

解决你的问题,你可以计算出最后的管理位置和当前一个之间的距离触发您onProgressChanged

private static final float MOVE_PRECISION = 5; // You may want to tune this parameter 
private float lastY; 

// ... 

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

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      lastY = event.getY(); 

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

       lastY = event.getY(); 
      } 
      break; 
     case MotionEvent.ACTION_UP: 
      myListener.onStopTrackingTouch(this); 
      break; 

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

private float calculateDistanceY (MotionEvent event) { 
    return Math.abs(event.getY() - lastY); 
} 
相关问题