Как сделать слайд, чтобы разблокировать кнопку в 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>