如何在android中制作幻灯片解锁按钮

时间:2013-02-16 12:20:45

标签: android

您好我想要一个按钮,该按钮应该可以作为IOS的“滑动解锁”按钮

简而言之,我想要一个没有点击效果的按钮,但是在拖动和拖动完成时可以从左向右滑动它应该考虑点击。

如果可能,请建议我使用任何示例代码。

谢谢!

11 个答案:

答案 0 :(得分:27)

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

        }
    });

答案 1 :(得分:16)

我开始使用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();
        }
    });

答案 2 :(得分:1)

有一些很好的库可以帮您解决问题。 如果使用库执行此操作对您来说不是问题,那么请考虑尝试以下方法:

https://github.com/cortinico/slidetoact

enter image description here

编码愉快!!! :)

答案 3 :(得分:0)

Android提供的Switch小部件类似于幻灯片解锁。但是,您必须稍微自定义它,例如禁用点击更改。

答案 4 :(得分:0)

出于某种原因,我无法禁用触摸操作,因此仍然可能意外点击 我提出了这个解决方案,它基本上不允许每次更改事件超过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);         
    }
});

答案 5 :(得分:0)

从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)组成一个布局,但它是一个简单的可配置解决方案,用于内置文本的幻灯片按钮。 我希望这对某人有用。

答案 6 :(得分:0)

可能很晚但我为此目的创建了一个小型库。它允许您从xml滑动和自定义按钮的行为。 Slide Button

基本上它涉及覆盖onTouch()事件并根据接收的坐标进行更改。之后,根据需要设置背景并自定义文本,这很简单。

答案 7 :(得分:0)

您可以使用此库快速轻松地自定义解锁。

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

Slide to unlock screenshort

答案 8 :(得分:0)

您可以重建正常的SeekBar来执行您想要的操作:

使用:

  • 起点(20)
  • 交叉线(90)
  • 并自动重置。

    seekBar.setOnSeekBarChangeListener(     new SeekBar.OnSeekBarChangeListener(){         整数点= 0;         整数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);
    }
}

答案 9 :(得分:0)

我希望在Ans下面工作,

.mat-radio-button.mat-accent.mat-radio-checked .mat-radio-outer-circle{
  border-color:rgb(66, 134, 244); 
}

.mat-radio-button.mat-accent .mat-radio-inner-circle{
  color:rgb(66, 134, 244);
  background-color:rgb(66, 134, 244) ;
}

.mat-radio-button.mat-accent .mat-radio-ripple .mat-ripple-element {
    background-color:rgb(255, 37, 37,.26)
}

答案 10 :(得分:0)

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

拇指

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