How to make slide to unlock button in android

前端 未结 11 521
心在旅途
心在旅途 2020-12-23 18:05

Hi I want a button that should work as \'slide to unlock\' button of IOS

in short I want a button that has no click effect but can slide left to right while drag and

相关标签:
11条回答
  • 2020-12-23 18:20

    For some reason, I couldn't disable the touch action so accidental taps are still possible
    I came up with this solution, it basically won't allow changing the progress by more than 10 values per change event

    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);         
        }
    });
    
    0 讨论(0)
  • 2020-12-23 18:20

    You can rebuild the normal SeekBar to do what you want:

    With:

    • Starting point (20)
    • Crossing line (90)
    • And auto reset.

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

    And:

    /**
     * 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);
        }
    }
    
    0 讨论(0)
  • 2020-12-23 18:23

    It maybe very late but I have created a small library for this very purpose. It allows you to swipe and customise the behaviour of your button from xml. Slide Button

    Basically it involves overriding of the onTouch() event and making changes according to the coordinates that are received. Its a simple thing after that to set the background as you want and customise the text.

    0 讨论(0)
  • 2020-12-23 18:25

    Starting from Oskar's answer (thanks for your contribute) i create a simple example project to manage Slide Button (horizontal and vertical) : https://github.com/rcaboni/AndroidSlideButton

    For a screen shot : https://raw.githubusercontent.com/rcaboni/AndroidSlideButton/master/screenshot.jpg

    This is the main method :

    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 for vertical button :

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

    It's not a real complete widget because is composed from two view (TextView and SlideButton) into a Layout, but it's a easy configurable solution for Slide Button with text inside. I hope this is useful for someone.

    0 讨论(0)
  • 2020-12-23 18:28

    Thanks, @Oskar Lundgren for the answer I have updated some of the things and if anybody is looking to do the same in kotlin. Here it is

    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>
    

    Progress Track

    <?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>
    
    0 讨论(0)
  • 2020-12-23 18:30

    I started out with the example that Jignesh Ansodariya posted, but as Aerrow points out, the user can click anywhere on the SeekBar to unlock. That makes it quite unusable, since the point with having a slide button is that accidental clicks should be ignored. My solution was to create a subclass of SeekBar, like this:

    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>
    

    And finally the code inside my Activity:

        ((SlideButton) findViewById(R.id.unlockButton)).setSlideButtonListener(new SlideButtonListener() {  
            @Override
            public void handleSlide() {
                unlockScreen();
            }
        });
    
    0 讨论(0)
提交回复
热议问题