簡體   English   中英

如何在android中滑動解鎖按鈕

[英]How to make slide to unlock button in android

嗨,我想要一個可以用作 IOS 的“滑動解鎖”按鈕的按鈕

簡而言之,我想要一個沒有點擊效果但可以在拖動時從左向右滑動的按鈕,並且在拖動完成時應該考慮點擊。

如果可能,請給我建議任何示例代碼。

謝謝!

首先,我要感謝@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));
            }

        }
    });

我從 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();
        }
    });

有一些很好的庫可以為您解決問題。 如果使用庫來執行此操作對您來說不是問題,請考慮嘗試以下方法:

https://github.com/cortinico/slidetoact

在此處輸入圖片說明

快樂編碼.. !! :)

Android 提供了類似於滑動解鎖Switch小部件。 但是,您必須對其進行一些自定義,例如禁用單擊更改。

您可以使用此庫快速輕松地自定義您的解鎖。

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

滑動解鎖屏幕短片

出於某種原因,我無法禁用觸摸操作,因此仍然可能會意外點擊
我想出了這個解決方案,它基本上不允許每個更改事件更改超過 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);         
    }
});

從奧斯卡的回答開始(感謝您的貢獻),我創建了一個簡單的示例項目來管理滑動按鈕(水平和垂直): 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)組成的一個布局,但它是一個簡單的可配置解決方案,用於內部帶有文本的滑動按鈕。 我希望這對某人有用。

可能很晚了,但我為此創建了一個小型圖書館。 它允許您從 xml 滑動和自定義按鈕的行為。 滑動按鈕

基本上它涉及覆蓋 onTouch() 事件並根據接收到的坐標進行更改。 之后,根據需要設置背景並自定義文本是一件簡單的事情。

您可以重建正常的 SeekBar 來執行您想要的操作:

和:

  • 起點 (20)
  • 交叉線 (90)
  • 並自動復位。

    seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() { Integer point = 0; Integer startPoint = 0; boolean started = 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);
    }
}

我希望下面的答案是工作,

    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>

謝謝,@Oskar Lundgren 的回答我已經更新了一些內容,如果有人希望在 kotlin 中做同樣的事情。 這里是

滑動確認

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

拇指

<?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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM