Как сделать слайд, чтобы разблокировать кнопку в android

Привет, я хочу кнопку, которая должна работать как кнопка "слайд для разблокировки" IOS

Короче говоря, я хочу кнопку, которая не имеет эффекта щелчка, но может перемещаться влево и вправо при перетаскивании и при завершении перетаскивания должна считаться нажатой.

пожалуйста, предложите мне любой пример кода, если это возможно.

Спасибо!

Ответ 1

Прежде всего, я хотел бы поблагодарить @matthias за его ответ. Я использовал следующую строку поиска с некоторой настройкой:

 <SeekBar
        android:id="@+id/myseek"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:clickable="false"
        android:max="100"
        android:progressDrawable="@android:color/transparent"
        android:thumb="@drawable/ic_launcher" />

и в java-коде

sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

            if (seekBar.getProgress() > 95) {

            } else {

                seekBar.setThumb(getResources().getDrawable(R.drawable.ic_launcher));
            }

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {


        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                boolean fromUser) {
            if(progress>95){
                seekBar.setThumb(getResources().getDrawable(R.drawable.load_img1));
            }

        }
    });

Ответ 2

Я начал с примера, который опубликовал Jignesh Ansodariya, но, как указывает Aerrow, пользователь может щелкнуть в любом месте SeekBar для разблокировки. Это делает его совершенно непригодным, поскольку точка с кнопкой слайда заключается в том, что случайные клики следует игнорировать. Моим решением было создать подкласс SeekBar, например:

public class SlideButton extends SeekBar {

    private Drawable thumb;
    private SlideButtonListener listener;

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

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (thumb.getBounds().contains((int) event.getX(), (int) event.getY())) {
                super.onTouchEvent(event);
            } else
                return false;
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            if (getProgress() > 70)
                handleSlide();

            setProgress(0);
        } else
            super.onTouchEvent(event);

        return true;
    }

    private void handleSlide() {
        listener.handleSlide();
    }

    public void setSlideButtonListener(SlideButtonListener listener) {
        this.listener = listener;
    }   
}

public interface SlideButtonListener {
    public void handleSlide();
}

XML:

        <package.SlideButton
            android:id="@+id/unlockButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="false"
            android:max="100"
            android:progressDrawable="@android:color/transparent"
            android:thumb="@drawable/button_lock" >
        </package.SlideButton>

И, наконец, код внутри моей Activity:

    ((SlideButton) findViewById(R.id.unlockButton)).setSlideButtonListener(new SlideButtonListener() {  
        @Override
        public void handleSlide() {
            unlockScreen();
        }
    });

Ответ 3

Есть несколько хороших библиотек, которые помогут вам. Если использование библиотеки для этого не является проблемой, подумайте над тем, чтобы попробовать это:

https://github.com/cortinico/slidetoact

enter image description here

Удачного кодирования.. !! :)

Ответ 4

Android предоставляет Switch виджет, похожий на слайд для разблокировки. Однако вам придется немного настроить его, например. отключить изменение при нажатии.

Ответ 5

По какой-то причине я не мог отключить действие касания, так что случайные краны все еще возможны
Я придумал это решение, оно в основном не позволит изменить ход более чем на 10 значений за событие изменения

int unlockLastSeekVal = 0;
// there are skips btwn changes, use value greater than 1
// 10 is great for seekbars with 100 values
int unlockSeekSensitivity = 10;
// final stage to "unlock"; 0.9 => 90%
Double unlockFinalStage = 0.9;
//...........
unlock.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser){
            if (Math.abs(unlockLastSeekVal - progress) > unlockSeekSensitivity){
                // too much delta, revert to last value
                seekBar.setProgress(unlockLastSeekVal);
            }else{
                unlockLastSeekVal = progress;
            }
        }
    }

    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    public void onStopTrackingTouch(SeekBar seekBar) {
        if (seekBar.getProgress() > seekBar.getMax() * unlockFinalStage){
            DoYourThing();
        }
        unlockLastSeekVal = 0;
        seekBar.setProgress(0);         
    }
});

Ответ 6

Начиная с ответа Oskar (спасибо за ваш вклад), я создаю простой пример для управления слайдовой кнопкой (горизонтальной и вертикальной): https://github.com/rcaboni/AndroidSlideButton

Для снимка экрана: https://raw.githubusercontent.com/rcaboni/AndroidSlideButton/master/screenshot.jpg

Это основной метод:

public boolean onTouchEvent(MotionEvent event) {
    if (!isEnabled()) {
        return false;
    }
    if (orientation == ORIENTATION_HORIZONTAL) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            int x= (int) event.getX();
            int y= (int) event.getY();
            if (thumb.getBounds().contains((int) event.getX(), (int) event.getY())) {
                super.onTouchEvent(event);
            } else
                return false;
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            if (getProgress() > 70)
                handleSlide();

            setProgress(0);
        } else
            super.onTouchEvent(event);
    }else{
        int i=0;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    int x= (int) event.getX();
                    int y= (int) event.getY();
                    if (!thumb.getBounds().contains((int) event.getY(), (int) event.getX())) {
                        return false;
                    }
                }
            case MotionEvent.ACTION_MOVE:
                i=getMax() - (int) (getMax() * event.getY() / getHeight());
                setProgress(100 - i);
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                break;
            case MotionEvent.ACTION_UP:
                i=getMax() - (int) (getMax() * event.getY() / getHeight());
                if (i < 30) {
                    handleSlide();
                }
                setProgress(0);
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                break;

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

XML для вертикальной кнопки:

<RelativeLayout
    android:layout_width="75dp"
    android:layout_height="130dp"
    android:background="@drawable/slide_background_green"
    android:id="@+id/lSlideButtonV"
    android:layout_below="@+id/lSlideButton"
    android:layout_marginTop="50dp">
    <TextView
        android:layout_width="20dp"
        android:layout_height="match_parent"
        android:text="SOS"
        android:id="@+id/tvSlideActionV"
        android:gravity="center|bottom"
        android:layout_alignParentRight="false"
        android:layout_alignParentEnd="false"
        android:layout_alignParentLeft="false"
        android:layout_alignParentStart="false"
        android:textSize="20dp"
        android:textColor="@android:color/white"
        android:layout_alignParentTop="false"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="false"
        android:layout_marginBottom="15dp" />
    <it.aldea.android.widget.SlideButton
        android:id="@+id/unlockButtonV"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:clickable="false"
        android:max="100"
        slideButton:orientation="vertical"
        android:progressDrawable="@android:color/transparent"
        android:thumb="@drawable/slide_track_red"
        android:indeterminate="false"
        android:layout_marginRight="5dp"
        android:layout_marginTop="20dp"
        android:layout_centerInParent="true"
        android:layout_marginBottom="10dp"
        android:thumbOffset="-2dp">
    </it.aldea.android.widget.SlideButton>

</RelativeLayout>

Это не полный виджет, потому что он состоит из двух видов (TextView и SlideButton) в макет, но это легко настраиваемое решение для кнопки Slide с текстом внутри. Надеюсь, что это кому-то полезно.

Ответ 7

Возможно, очень поздно, но я создал небольшую библиотеку для этой цели. Он позволяет прокручивать и настраивать поведение вашей кнопки из xml. Кнопка слайда

В основном это связано с переопределением события onTouch() и внесением изменений в соответствии с полученными координатами. Его простая вещь после этого, чтобы установить фон, как вы хотите, и настроить текст.

Ответ 8

Вы можете использовать эту библиотеку, чтобы быстро и легко настроить свою разблокировку.

https://github.com/cheekiat/SlideToUnlock

Используйте этот код в xml

 <cheekiat.slideview.SlideView
        android:id="@+id/slide_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:slideBackground="@drawable/orangesquarebutton"
        app:slideSrc="@drawable/slide_image"
        app:slideText="Slide to unlock"
        app:slideTextColor="#ffffff"
        app:slideTextSize="10dp" />

Слайд для разблокировки экранов

Ответ 9

Вы можете восстановить нормальный SeekBar, чтобы сделать то, что хотите:

С

  • Начальная точка (20)
  • Линия пересечения (90)
  • И авто reset.

    seekBar.setOnSeekBarChangeListener(   новый SeekBar.OnSeekBarChangeListener() {       Целочисленная точка = 0;       Integer startPoint = 0;       boolean start = true;

        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean wasUserInput) {
            point = i;
    
            if (started && i > 0 && wasUserInput) {
                startPoint = new Integer(i);
                started = false;
            }
        }
    
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }
    
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            if (point > 90 && startPoint < 20) { // slided to the right correctly.
                // TODO::
    
            } else { // reset.
                resetSeekBar(seekBar, point);
            }
    
            startPoint = 0;
            started = true;
        }
    });
    

и

/**
 * Resetting the seekbar, on point at a time.
 * @param seekBar                           Reference to the seekbar made smaller.
 * @param oldPoint                          The point where the dot is atm.
 */
private void resetSeekBar(final SeekBar seekBar, final int oldPoint) {
    if (oldPoint > 0) {
        final int newPoint = oldPoint -1;
        seekBar.setProgress(newPoint);

        timer.schedule(new TimerTask() {
            final SeekBar seekBar = seekBarBid;
            @Override
            public void run() {
                resetSeekBar(seekBar, newPoint);
            }
        }, 3);

    } else {
        seekBar.setProgress(oldPoint);
    }
}

Ответ 10

Надеюсь, ниже Ans это работа,

    public class UnlockSliderView extends FrameLayout {
    @BindView(R2.id.tv_unlock_slider)
    TextView tvUnlockSlider;

    @BindView(R2.id.iv_circle_slide)
    ImageView ivCircleSlide;

    private View parentCircle;

    private float xOrigin = 0;
    private float xOriginCircle = 0;
    private boolean circleTouched = false;

    public UnlockSliderView(Context context) {
        super(context);
        init();
    }

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

    public UnlockSliderView(Context context, AttributeSet attr, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        inflate(getContext(), R.layout.layout_unlock_slider_view, this);
        ButterKnife.bind(this);

        parentCircle = (View) ivCircleSlide.getParent();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            eventActionDown(event);
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            eventActionMove(event);
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            unlockFinish();
        }
        return true;
    }

    private void eventActionDown(MotionEvent event) {
        if ((event.getX() >= ivCircleSlide.getX() && event.getX() <= ivCircleSlide.getX() + ivCircleSlide.getWidth())
                && (event.getY() >= ivCircleSlide.getY() && event.getY() <= ivCircleSlide.getY() + ivCircleSlide.getHeight())) {
            xOrigin = event.getX();
            xOriginCircle = ivCircleSlide.getX();
            circleTouched = true;
        } else {
            circleTouched = false;
        }
    }

    private void eventActionMove(MotionEvent event) {
        if (circleTouched) {
            float newXCircle = xOriginCircle + (event.getX() - xOrigin);
            newXCircle = (newXCircle < xOriginCircle) ? xOriginCircle : newXCircle;
            newXCircle = (newXCircle > parentCircle.getWidth() - ivCircleSlide.getWidth() - xOriginCircle) ? parentCircle.getWidth() - ivCircleSlide.getWidth() - xOriginCircle : newXCircle;
            float alpha = 1 - ((newXCircle - xOriginCircle) / (parentCircle.getWidth() - ivCircleSlide.getWidth() - (xOriginCircle * 2)));
            tvUnlockSlider.setAlpha(alpha);
            ivCircleSlide.setX(newXCircle);
            if (newXCircle == parentCircle.getWidth() - ivCircleSlide.getWidth() - xOriginCircle) {
                unlockFinish();
                if (mListener != null) mListener.onUnlock();
            }
        }
    }

    private void unlockFinish() {
        if (circleTouched) {
            ivCircleSlide.animate().x(xOriginCircle).setDuration(400).start();
            tvUnlockSlider.animate().alpha(1).setDuration(400).start();
            circleTouched = false;
        }
    }




   and the xml is,

  <?xml version="1.0" encoding="utf-8"?>
   <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="@dimen/unlock_slider_height"
    android:layout_margin="@dimen/default_padding"
    android:background="@drawable/btn_slider_back"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="4dp">

    <TextView
        android:id="@+id/tv_unlock_slider"
        style="@style/prelogin_slider"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="@dimen/unlock_slider_handle_size"
        android:layout_marginStart="@dimen/unlock_slider_handle_size"
        android:text="@string/logon_to_mobile_banking" />

    <ImageView

        android:id="@+id/iv_circle_slide"
        android:layout_width="@dimen/unlock_slider_handle_size"
        android:layout_height="@dimen/unlock_slider_handle_size"
        android:scaleType="fitCenter"
        android:src="@drawable/btn_slider_handle"
        tools:ignore="ContentDescription" />

</FrameLayout>

Ответ 11

Спасибо, @Oskar Lundgren за ответ я обновил некоторые вещи, и если кто-то хочет сделать то же самое в kotlin. Здесь это

SlideToConfirm

class SlideToConfirm : SeekBar, SeekBar.OnSeekBarChangeListener {

    private lateinit var listener: SlideButtonListener

    // To prevent the thumb to going out of track
    private val maxProgress = 91
    private val minProgress = 9

    constructor(context: Context) : super(context) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
        init()
    }

    fun init() {
        setDrawables()
        setProperties()
        setOnSeekBarChangeListener(this)
    }

    private fun setDrawables() {
        thumb = ContextCompat.getDrawable(context, R.drawable.slider_thumb)
        progressDrawable = ContextCompat.getDrawable(context, R.drawable.slider_progress_drawable)
    }

    private fun setProperties() {
        isClickable = false
        splitTrack = false
        setPadding(0, 0, 0, 0)
        progress = minProgress
    }

    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
        if (progress < minProgress) {
            this.progress = minProgress
        }
        if (progress > maxProgress) {
            this.progress = maxProgress
        }
    }

    override fun onStartTrackingTouch(seekBar: SeekBar?) {}

    override fun onStopTrackingTouch(seekBar: SeekBar?) {}

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event!!.action == MotionEvent.ACTION_DOWN) {
            if (thumb.bounds.contains(event.x.toInt(), event.y.toInt())) {
                super.onTouchEvent(event)
            } else
                return false
        } else if (event.action == MotionEvent.ACTION_UP) {
            if (progress > 70) {
                handleSlide()
                progress = maxProgress
            } else {
                progress = minProgress
            }
        } else {
            super.onTouchEvent(event)
        }
        return true
    }

    fun setOnSlideListener(listener: SlideButtonListener) {
        this.listener = listener
    }

    private fun handleSlide() {
        listener.handleSlide()
    }

    interface SlideButtonListener {
        fun handleSlide()
    }
}

Thumb

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <solid android:color="@color/cyan" />
            <corners android:radius="8dp" />
            <size
                android:width="50dp"
                android:height="50dp" />
        </shape>
    </item>
    <item android:drawable="@drawable/ic_arrow_forward_white" />
</layer-list>

Трек прогресса

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="35dp" />
    <size
        android:width="100dp"
        android:height="50dp" />
    <stroke
        android:width="1dp"
        android:color="@color/errorRed" />
    <solid android:color="@android:color/white" />
</shape>