防止单击更改SeekBar进度

12

我在Android应用中使用了一个SeekBar。当用户在SeekBar上单击任何位置时,进度值会改变。我希望只有在用户滑动SeekBar的滑块时才会改变进度值(就像iOS中的UISlider一样)。

我尝试将SeekBarclickable属性设置为false,但没有起作用。我该如何实现所需的行为?

13个回答

10

这个星期我也遇到了同样的问题,我使用自定义SeekBar解决了它:

以下是我的代码:

public class Slider extends SeekBar {

private Drawable mThumb;

public Slider(Context context) {
    super(context);

}

public Slider(Context context, AttributeSet attrs) {
    super(context, attrs);

}

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

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {

        if (event.getX() >= mThumb.getBounds().left
                && event.getX() <= mThumb.getBounds().right
                && event.getY() <= mThumb.getBounds().bottom
                && event.getY() >= mThumb.getBounds().top) {

            super.onTouchEvent(event);
        } else {
            return false;
        }
    } else if (event.getAction() == MotionEvent.ACTION_UP) {
        return false;
    } else {
        super.onTouchEvent(event);
    }

    return true;
}}

希望这能有所帮助


4
FTW: thumb.getBounds().contains((int)event.getX(), (int)event.getY())翻译:判断thumb的边界是否包含指定的坐标点(event.getX(), event.getY())。 - greg7gkb
1
尝试了这个解决方案,它解决了标题信息的问题,但会导致缩略图大小意外改变,例如更大的缩略图大小。 - Arduino

8

请查看另一个帖子:

用户无法与SeekBar交互

我尝试了以下方法,效果很好。请注意我的SeekBar设置了android:max属性为100,如下所示:


<SeekBar
android:id="@+id/EnableBar"
android:layout_span="2"
android:max="100"
/>

package com.androidbook.hiworld;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.SeekBar;


public class HiWorldActivity extends Activity {
    int originalProgress;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        SeekBar seek = (SeekBar)findViewById(R.id.EnableBar);

        seek.setOnSeekBarChangeListener(
        new SeekBar.OnSeekBarChangeListener() {
           public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
               ((TextView)findViewById(R.id.SeekTxt)).setText("Value: "+progress);
               if(fromTouch == true){
                  // only allow changes by 1 up or down
                  if ((progress > (originalProgress+24))
                       || (progress < (originalProgress-24))) {
                     seekBar.setProgress( originalProgress);
                  } else {
                      originalProgress = progress;
                  }
               } 
           }

           @Override
           public void onStopTrackingTouch(SeekBar seekBar) {
               //Nothing here..                
           }

           @Override
           public void onStartTrackingTouch(SeekBar seekBar) {
               originalProgress = seekBar.getProgress();
           }
        });
    }
}

为什么这个值要加减 24? - vallllll

3

虽然有点晚,但或许对某些人还是有用的解决方案。我扩展了自定义SeekBar并重写了onTouchEvent。

package com.timera.android.common.view;

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

public class OnlySeekableSeekBar extends SeekBar {

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

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

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

@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        final int width = getWidth();
        final int available = width - getPaddingLeft() - getPaddingRight();
        int x = (int) event.getX();
        float scale;
        float progress = 0;
        if (x < getPaddingLeft()) {
            scale = 0.0f;
        } else if (x > width - getPaddingRight()) {
            scale = 1.0f;
        } else {
            scale = (float) (x - getPaddingLeft()) / (float) available;
        }
        final int max = getMax();
        progress += scale * max;
        if (progress < 0) {
            progress = 0;
        } else if (progress > max) {
            progress = max;
        }

        if (Math.abs(progress - getProgress()) < 10)
            return super.onTouchEvent(event);
        else
            return false;
    default:
        return super.onTouchEvent(event);
    }
}
}

1
这个代码可以与SeekBar内的事件监听器完美配合使用。
PS. 我对这个代码进行了改进,使其更加通用化。
/**
 * ProtectedSeekBar
 * 01/27/15
 */
public class ProtectedSeekBar extends SeekBar {

    private Drawable mThumb;

    public ProtectedSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

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

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            if( event.getX() < mThumb.getBounds().left ||
                event.getX() > mThumb.getBounds().right ||
                event.getY() > mThumb.getBounds().bottom ||
                event.getY() < mThumb.getBounds().top) {
                return false;
            }
        }
        return super.onTouchEvent(event);
    }
}

“SeekBar”暴露了一个“getThumb”方法,这是否消除了您自己存储拇指可绘制对象的需求? - stkent
1
@stkent SeekBar.getThumb 在 API >= 16 中已经公开。因此,如果您不需要向后兼容性,则可以删除该方法。 - zinuzoid

1

我想到了一个解决方案,虽然不是很美观,但应该能解决问题...

这是我的想法:

  1. 创建一个无形的覆盖层,覆盖滑块除拇指按钮外的所有部分

    (我使用了一个黑色的 seekbar 作为覆盖层)

  2. 当按下拇指时,在滑块上调用 'bringToFront' 方法

  3. 当松开拇指时,在无形的覆盖层上调用 'bringToFront' 方法

请注意,为使此方法有效,您必须更改覆盖层的大小,以便它覆盖除拇指按钮外的所有内容(我建议使用两个覆盖层[一个用于拇指按钮的每一侧])

当您释放拇指按钮时,应调整覆盖层的大小

... 就像我说的,这并不美观。我相信有更好的方法来解决这个问题,但如果你必须这样做,我会尝试这种方法。

   yourBarChangeListener yourBarChangeListener = new SeekBar.OnSeekBarChangeListener() { 

    @Override 
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
     } 

    @Override 
    public void onStartTrackingTouch(SeekBar seekBar) {
     // YOUR CODE HERE 
    } 
    @Override 
    public void onStopTrackingTouch(SeekBar seekBar) { 
    } 
}; 
yourBar.setOnSeekBarChangeListener(yourBarChangeListener);

当拇指按下时,您如何检测到它? - bugfixr
`yourBarChangeListener yourBarChangeListener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { // YOUR CODE HERE } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }; yourBar.setOnSeekBarChangeListener(yourBarChangeListener);` - bornSwift
谢谢,这完全是一种hack方法。对我有用。 - Anupam

0
通过这段代码,您可以禁用用户移动缩略图。
     SeekBar progress = (SeekBar) findViewById(R.id.timer);
      seekBar.setProgress(time);

其中"time"是一个整数变量,保存着进度

     progress.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                boolean fromUser) {
            if(fromUser){
                seekBar.setProgress(time);
            }

        }
    });

0

如果要禁用seebBar上的单击操作,您可以观察DOWN和UP事件之间的时间,通常单击持续时间少于100毫秒。

seekBar.setOnTouchListener(new View.OnTouchListener() {
      private long startTime = 0;
      private long endTime = 0;

      @Override
      public boolean onTouch(View view, MotionEvent motionEvent) {

        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
          startTime = motionEvent.getEventTime();
          return true;
        }
        if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
          endTime = motionEvent.getEventTime();
          if (Math.abs(startTime-endTime)<=100)
            return true;
          else
            return false;
        }
        Log.d(TAG, String.valueOf(motionEvent.getEventTime()));
        return false;
      }
    });

0
我遇到的情况是SeekBar是由另一段代码创建的,因此我无法创建一个带有onTouchEvent()处理程序的子类。相反,我覆盖了我想要操作的实例的OnTouchListener...
SeekBar sb = (SeekBar) findViewById(R.id.seekbar);

sb.setOnTouchListener(new OnTouchListener()
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Drawable thumb = ((SeekBar) v).getThumb();

        if (   event.getX() < thumb.getBounds().left
            || event.getX() > thumb.getBounds().right
            || event.getY() < thumb.getBounds().top
            || event.getY() > thumb.getBounds().bottom) {
            // event occurred outside the thumb slider so ignore it
            return true;
        } else {
            // event occurred inside the thumb slider so pass it on
            return false;
        }
    }
});

是的,我可以简单地返回“if”表达式的内容,但这并不会使代码易读。


0

看了一下@lordmegamax的代码,发现有些地方不起作用。

  1. int oldProgress不能放在onCreate里面,你需要在外面声明。
  2. 如果seekBar总是从头开始,onStartTrackingTouch将始终返回0,所以你的onStopTrackingTouch永远不会起作用。

稍微思考了一下,我找到了一个解决办法。

//SeekBar Slide
    skbLogin.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
        //Force Slide From Beginning
        public void onStartTrackingTouch(SeekBar seekBar) { continuosProgress = false; }
        //Execute when reach the max
        public void onStopTrackingTouch(SeekBar seekBar) {
            if(continuosProgress)
                if(seekBar.getProgress() == 100) btnLogin();
                else skbRollBack();
            else
                seekBar.setProgress(0);
        }
        //Check Slide from Beginning
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if(progress < 10) continuosProgress = true;
        }
    });

希望能对您有所帮助。 最好的问候。
附言:这是我的第一篇帖子,如果我做错了什么,请见谅。

0

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