Я разрабатываю киоск и теперь в админке. Чтобы перейти к администратору, пользователю нужно нажать экран 5 раз всего за 3 секунды или иначе, ничего не произойдет. Может ли кто-нибудь помочь мне с этой проблемой? Заранее спасибо!
Нажмите на экран 5 раз в 3 секунды в android
Ответ 1
Пожалуйста, прочитайте комментарии в коде, это довольно просто
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
public class MainActivity extends Activity {
private int count = 0;
private long startMillis=0;
//detect any touch event in the screen (instead of an specific view)
@Override
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
if (eventaction == MotionEvent.ACTION_UP) {
//get system current milliseconds
long time= System.currentTimeMillis();
//if it is the first time, or if it has been more than 3 seconds since the first tap ( so it is like a new try), we reset everything
if (startMillis==0 || (time-startMillis> 3000) ) {
startMillis=time;
count=1;
}
//it is not the first, and it has been less than 3 seconds since the first
else{ // time-startMillis< 3000
count++;
}
if (count==5) {
//do whatever you need
}
return true;
}
return false;
}
}
Ответ 2
Мое решение похоже на Андреса. Обратный отсчет начинается, когда вы поднимаете палец в первый раз, то есть, когда я считаю, что краны должны быть закончены. Это похоже на клики, щелчок происходит, когда вы отпускаете кнопку мыши. Через 3 секунды после первого подъема счетчик сбрасывается. Andres approch, с другой стороны, использует логику, основанную на том, чтобы перенести палец на экран. Он также использует дополнительный поток.
Моя логика - одна из многих возможных. Другим разумным подходом было бы обнаружить 5 последовательных отводов в течение 3 секунд в потоке кранов. Рассматривать:
tap1, 2000ms, tap2, 500ms, tap3, 550ms, tap4, 10ms, tap5, 10ms, tap6.
Второй через шестой отвод включает в себя набор из пяти ответвлений менее чем за 3 секунды; в моем подходе это не будет обнаружено. Чтобы обнаружить это, вы можете использовать очередь FIFO фиксированного размера 5 и помнить последние 5 временных меток: эта последовательность увеличивается. Когда вы получаете новый ответ, вы проверяете, есть ли 1) произошло не менее 5 ответвлений, и 2) самая старая временная метка не старше, чем 3 секунды.
В любом случае, вернемся к первой логике, поместите этот код в Activity
:
private int mCounter = 0;
private Handler mHandler = new Handler();
private Runnable mResetCounter = new Runnable() {
@Override
public void run() {
mCounter = 0;
}
};
@Override
public boolean onTouchEvent(MotionEvent event) {
switch(MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mCounter == 0)
mHandler.postDelayed(mResetCounter, 3000);
mCounter++;
if (mCounter == 5){
mHandler.removeCallbacks(mResetCounter);
mCounter = 0;
Toast.makeText(this, "Five taps in three seconds", Toast.LENGTH_SHORT).show();
}
return false;
default :
return super.onTouchEvent(event);
}
}
Примечание. Вероятно, вы захотите также сохранить состояние при изменении конфигурации. Как сказал бы математик, я допускаю это как упражнение для читателя
Ответ 3
Переопределите метод Activity onTouchEvent()
чтобы получать события касания с экрана. Каждый раз, когда пользователь нажимает на экран приращение переменной и откладывает Runnable за 3 секунды, если это первый раз, когда вы касаетесь, если через 3 секунды события касания будут очищены, и ничего не произойдет. Поток проверяет, что число событий касания равно 5 или более, если они произошли до 3 секунд, переменная не очищается, и if(touchEvent >= 5)
истинно. Я не проверял его! Но он полностью асинхронный :)
// Touch events on screen
@Override
public boolean onTouchEvent(MotionEvent event) {
// User pressed the screen
if(event.getAction() == MotionEvent.ACTION_DOWN){
if(touchEvent == 0) myView.post(mRunnable, 3000); // Execute a Runnable in 3 seconds
++touchEvent;
}
return false;
}
Runnable mRunnable = new Runnable(){
@Override
public void run() {
touchEvent = 0; // 3 seconds passed, clear touch events
}
}
Thread mThread = new Thread(new Runnable(){
@Override
public void run(){
if(touchEvent >= 5){
// Touched 5 times in 3 seconds or less, CARE this is not UI Thread!
}
}
});
mThread.start();
Ответ 4
private int touchSequenceCount = 0;
private Handler handlerTouchSequenceDetection;
private Runnable runnableTouchSequenceDetection;
public void setupTouchSequenceDetection(final View view){
try {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d("setupTouchSequenceDetection", "touchCount: " + (touchSequenceCount+1));
if(touchSequenceCount == 0){
handlerTouchSequenceDetection.postDelayed(runnableTouchSequenceDetection, 2000);
}else{
if(touchSequenceCount == 2){
new AlertDialog.Builder(Activity_CheckIn_SelectLanguage.this)
.setMessage("warning message here")
.setCancelable(true)
.setPositiveButton("yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
resetTouchSequenceDetection(true);
}
})
.setNegativeButton("no", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
resetTouchSequenceDetection(true);
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
resetTouchSequenceDetection(true);
}
})
.show();
}
}
touchSequenceCount = touchSequenceCount + 1;
break;
}
return false;
}
});
handlerTouchSequenceDetection = new Handler();
runnableTouchSequenceDetection = new Runnable() {
public void run() {
Log.d("setupTouchSequenceDetection", "reset touchCount: " + (touchSequenceCount+1));
resetTouchSequenceDetection(false);
}
};
}
catch(Exception ex){
if(ex != null){
}
}
}
private void resetTouchSequenceDetection(boolean removeRunnable){
try{
if(removeRunnable){
handlerTouchSequenceDetection.removeCallbacks(runnableTouchSequenceDetection);
}
touchSequenceCount = 0;
}
catch(Exception ex){
if(ex != null){
}
}
}