防止单击改变SeekBar进度

时间:2011-02-26 09:24:11

标签: android android-seekbar android-touch-event

我在Android应用中使用SeekBar。当用户单击SeekBar上的任意位置时,其进度值会发生变化。我只希望在用户滑动SeekBar拇指时更改进度值(就像iOS中的UISlider一样)。

我已尝试将clickable的{​​{1}}属性设置为false,但这不起作用。我怎样才能达到预期的行为?

13 个答案:

答案 0 :(得分:9)

本周我遇到了同样的问题,我使用自定义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;
}}

希望这有帮助

答案 1 :(得分:8)

查看另一个帖子:

User can not interact with the 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();
           }
        });
    }
}

答案 2 :(得分:4)

现在为时已晚,但也许有人需要解决方案。我扩展自定义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);
    }
}
}

答案 3 :(得分:1)

我想出了一个解决方案,它不是很漂亮,但应该可以解决这个问题......

以下是这个想法:

  1. 创建一个不可见的叠加层,覆盖除拇指按钮以外的所有滑块

    (我使用黑色的搜索栏作为叠加层)

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

  3. 当拇指被释放时,在隐形覆盖
  4. 上调用'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);
    

答案 4 :(得分:0)

    int oldProgress;
    boolean isOn = true;
    vSeek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

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

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            if (oldProgress == seekBar.getProgress()) {
                if (isOn) {
                    seekBar.setThumb(getResources().getDrawable(R.drawable.blck_btn));
                    isOn = false;
                } else {
                    seekBar.setThumb(getResources().getDrawable(R.drawable.blck_btn_selected));
                    isOn = true;
                }
            }
        }

您可以比较停止跟踪时的进度。

答案 5 :(得分:0)

查看@lordmegamax代码,我发现有些东西不起作用。

  1. int oldProgress无法留在onCreate,你需要在外面声明它。
  2. 如果你的seekBar总是从头开始,onStartTrackingTouch将始终返回0,所以你的onStopTrackingTouch永远不会工作。
  3. 稍微思考一下,我找到了解决方案。

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

    希望它有所帮助。 最好的问候

    PS:这是我的第一篇文章,抱歉,如果我做错了。

答案 6 :(得分:0)

这个与SeekBar中的事件监听器完美配合。

PS。我从Slim改进了这个代码,使其更加通用。

/**
 * ProtectedSeekBar
 * 01/27/15
 *
 * @author Jetsada Machom <jim@imjim.im>
 */
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);
    }
}

答案 7 :(得分: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);
            }

        }
    });

答案 8 :(得分:0)

private class UpdateListener implements OnSeekBarChangeListener {

    // max step user can change at once
    private static final int THUMB_MAX_MOVE = 5;

    // current seekbar value (50 is initial seekbar value as defined in xml)
    private int currentProgress = 50;

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

        // save current value before user jumps around
        currentProgress = seekBar.getProgress();
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {}

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

        // check if we've jumped too far
        if (Math.abs(currentProgress - progress) > THUMB_MAX_MOVE) {

            // if so, revert to last progress and return
            seekBar.setProgress(currentProgress);
            return;
        }

        // if not, move was valid and update current progress
        currentProgress = progress;

        // do anything more here
    }
}

答案 9 :(得分:0)

我还没有看到的另一个选项建议:一个子类,它转换接收的动作事件,以使每个手势看起来都是从拇指的中心开始。这会对潜在的搜索栏行为产生以下影响:

  • 在适当位置敲击不会产生拇指移动(与其他建议的解决方案相同);
  • 执行从拇指开始远离的滑动手势仍然可以平滑地翻译拇指(与其他建议的解决方案不同)。

代码

/**
 * Translates every gesture to be centered at the current thumb location.
 */
public final class ThumbCentricSeekBar extends SeekBar {

    // Constructors go here...

    private Float offsetX;
    private Float offsetY;

    @Override
    public boolean onTouchEvent(final MotionEvent event) {
        if (event.getAction() == ACTION_DOWN && offsetX == null) {
            offsetX = getThumb().getBounds().centerX() - event.getX();
            offsetY = getThumb().getBounds().centerY() - event.getY();
        }

        event.offsetLocation(offsetX, offsetY);

        if (event.getAction() == ACTION_UP) {
            offsetX = null;
            offsetY = null;
        }

        return super.onTouchEvent(event);
    }

}

演示

显示触摸位置以说明我描述的行为。

enter image description here

答案 10 :(得分:0)

对于在seebBar上禁用单击,您可以在DOWN和UP事件之间观看时间,通常单击的持续时间小于100 ms。

  <script type="application/javascript">
     ... ga setup here

     <% if @ga_page.present? %>
        ga('set', 'page', '<%= @ga_page%>');
     <% end %>
     ga('send', 'pageview');
  </script>

答案 11 :(得分: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”表达式的内容,但这不能使代码可读。

答案 12 :(得分:0)

在此处查看答案。它仅允许通过拇指而不是可绘制进度来更改进度。 https://stackoverflow.com/a/62165116/1159930