Предотвратите одно касание от изменения прогресса SeekBar - PullRequest
9 голосов
/ 26 февраля 2011

Я использую SeekBar в своем приложении для Android. Когда пользователь нажимает в любом месте на SeekBar, его значение прогресса изменяется. Я хочу, чтобы значение прогресса изменялось только тогда, когда пользователь перемещает большой палец SeekBar (точно так же, как UISlider в iOS).

Я попытался установить для свойства clickable SeekBar значение false, но это не сработало. Как мне добиться желаемого поведения?

Ответы [ 12 ]

9 голосов
/ 08 июня 2013

На этой неделе я столкнулся с той же проблемой и решил ее с помощью пользовательского 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;
}}

Надеюсь, это поможет

8 голосов
/ 02 августа 2011

Проверьте эту другую тему:

Пользователь не может взаимодействовать с 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();
           }
        });
    }
}
4 голосов
/ 28 ноября 2013

Слишком поздно, но, возможно, кому-то понадобится решение.Я расширяю пользовательский 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 голос
/ 27 января 2015

Это прекрасно работает со слушателем событий в 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);
    }
}
1 голос
/ 22 апреля 2011

Я придумала решение, оно не очень красивое, но оно должно сработать ...

Вот идея:

  1. Создатьневидимое наложение, которое покроет все ползунки, кроме кнопки большого пальца

    (я использовал заштрихованную панель поиска, чтобы действовать как наложение)

  2. При нажатии большого пальцавызовите метод “takeToFront” на слайдере

  3. Когда большой палец отпущен, вызовите метод “takeToFront” для невидимого наложения

Обратите внимание, чтобы это работало, вы должны изменитьразмер наложения, чтобы он охватывал все, кроме кнопки большого пальца (я предлагаю использовать два наложения [по одному на каждую сторону кнопки большого пальца])

Когда вы отпустите кнопку большого пальца, вы должны затемизмените размер оверлеев

... как я уже сказал, это не красиво.Я уверен, что есть гораздо лучшие способы сделать это, но если вы должны это сделать, я бы попробовал это.

   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);
0 голосов
/ 21 ноября 2018

Ситуация, с которой я столкнулся, заключается в том, что 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;
        }
    }
});

Да, я мог бы просто вернуть содержимое выражения "если", но это не сделало бы код читабельным.

0 голосов
/ 22 сентября 2017

Для отключения однократного нажатия на seebBar вы можете наблюдать время между событиями ВНИЗ и ВВЕРХ, обычно продолжительность однократного нажатия менее 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 голосов
/ 02 марта 2017

Другой вариант, который я пока не предложил, - это подкласс, который переводит полученные события движения, чтобы каждый жест, казалось, начинался в центре большого пальца. Это оказывает следующее влияние на поведение панели поиска:

  • постукивание по месту не вызывает движения большого пальца (аналогично другим предлагаемым решениям);
  • выполнение жеста смахивания, который начинается на удалении от большого пальца, все еще может плавно переводить большой палец (в отличие от других предлагаемых решений).

код

/**
 * 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

0 голосов
/ 17 мая 2016
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
    }
}
0 голосов
/ 09 апреля 2015

С помощью этого кода вы можете отключить переход большого пальца пользователем

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

        }
    });
...