toques toque samsung para pantalla habilitar encender doble desbloqueo desbloquear con bloqueo bloquear app apagar activar android listview double-click

android - samsung - encender pantalla con dos toques



Android: ¿Cómo detectar el doble toque? (15)

Toca dos veces y toca un solo toque

Solo doble toque

Es bastante fácil detectar un doble toque en una vista usando SimpleOnGestureListener (como se demostró en la respuesta de Hannes Niederhausen ).

private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onDoubleTap(MotionEvent e) { return true; } }

No veo una gran ventaja para reinventar la lógica para esto (como la respuesta de bughi ).

Toca dos veces y toca un solo toque con retraso

También puede usar SimpleOnGestureListener para diferenciar un solo toque y un doble toque como eventos mutuamente excluyentes. Para hacerlo, solo anula onSingleTapConfirmed . Esto retrasará la ejecución del código de un solo toque hasta que el sistema esté seguro de que el usuario no ha hecho doble clic (es decir, el retraso> ViewConfiguration.getDoubleTapTimeout() ). Definitivamente no hay razón para reinventar toda la lógica para eso (como se hace en this , this y otras respuestas).

private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { return true; } @Override public boolean onDoubleTap(MotionEvent e) { return true; } }

Toca dos veces y toca un solo toque sin demora

El posible problema con onSingleTapConfirmed es la demora. A veces, un retraso notable no es aceptable. En ese caso, puede reemplazar onSingleTapConfirmed con onSingleTapUp .

private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public boolean onDoubleTap(MotionEvent e) { return true; } }

Sin embargo, onSingleTapUp onDoubleTap se onDoubleTap tanto a onSingleTapUp como a onDoubleTap si hay un doble toque. (Esto es esencialmente lo que hace la respuesta de bughi y de lo que algunos comentaristas se quejaban). O necesita usar el retraso o llamar a ambos métodos. No es posible tener un solo toque sin demora y al mismo tiempo saber si el usuario va a volver a tocar.

Si el retraso de un solo toque no es aceptable para usted, entonces tiene un par de opciones:

  • Acepte que tanto onSingleTapUp como onDoubleTap se onDoubleTap para un doble toque. Solo divida su lógica apropiadamente para que no importe. Esto es esencialmente lo que hice cuando implementé una doble pulsación para mayúsculas y minúsculas en un teclado personalizado.
  • No use un doble toque. No es una acción UI intuitiva para la mayoría de las cosas. Como sugiere Dave Webb , una larga presión es probablemente mejor. También puede implementar eso con SimpleOnGestureListener :

    private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { } }

Tengo un problema con la implementación del doble toque. Bueno, implementé onGestureListener y tuve el gestureDetector , pero no estoy seguro de dónde está el problema, aquí está mi código:

public class home extends TabActivity implements OnGestureListener { /** Called when the activity is first created. */ private EditText queryText; private ResultsAdapter m_adapter; private ProgressDialog pd; final Handler h = new Handler(); private TabHost mTabHost; private ArrayList<SearchItem> sResultsArr = new ArrayList<SearchItem>(); private String queryStr; private JSONObject searchResponse; private GestureDetector gestureScanner; final Runnable mUpdateResults = new Runnable() { public void run() { updateListUi(); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button search = (Button)findViewById(R.id.search); Button testButt = (Button)findViewById(R.id.testbutt); queryText = (EditText)findViewById(R.id.query); ListView lvr = (ListView)findViewById(R.id.search_results); //initialise the arrayAdapter this.m_adapter = new ResultsAdapter(home.this, R.layout.listrow, sResultsArr); lvr.setAdapter(this.m_adapter); lvr.setOnItemClickListener(new OnItemClickListener(){ @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false); } }); gestureScanner = new GestureDetector(this,this); gestureScanner.setOnDoubleTapListener(new OnDoubleTapListener(){ public boolean onDoubleTap(MotionEvent e) { //viewA.setText("-" + "onDoubleTap" + "-"); pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false); return false; } public boolean onDoubleTapEvent(MotionEvent e) { // viewA.setText("-" + "onDoubleTapEvent" + "-"); return false; } public boolean onSingleTapConfirmed(MotionEvent e) { //viewA.setText("-" + "onSingleTapConfirmed" + "-"); return false; } }); //initialise tab contents mTabHost = getTabHost(); mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Home").setContent(R.id.homepage)); mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Search Results").setContent(R.id.tab2)); mTabHost.setCurrentTab(0); //sets the respective listeners testButt.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { if(mTabHost.getTabWidget().getVisibility()==View.GONE){ mTabHost.getTabWidget().setVisibility(View.VISIBLE); } else{ mTabHost.getTabWidget().setVisibility(View.GONE); } } }); search.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { sResultsArr.clear(); queryStr = "http://rose.mosuma.com/mobile?query=" + queryText.getText().toString(); pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false); goSearch(); } }); } //updates the listUI whenever after receiving the response from the server public void updateListUi(){ if(sResultsArr.size() > 0){ } try{ String ptypename; int count; LinearLayout ptypebar = (LinearLayout)findViewById(R.id.productCat); ptypebar.removeAllViews(); JSONArray ptypes = searchResponse.getJSONArray("ptypes"); for(int index =0;index < ptypes.length();index++){ JSONObject ptype = ptypes.getJSONObject(index); count = ptype.getInt("count"); ptypename = ptype.getString("ptypename"); //add into tab 2''s UI //ImageView icon = new ImageView(this); TextView t = new TextView(home.this); t.setText(ptypename + " (" + count + ")"); ptypebar.addView(t); } } catch(JSONException e){ } //if(m_adapter.getItems() != sResultsArr){ ArrayList<SearchItem> a = m_adapter.getItems(); a = sResultsArr; //} m_adapter.notifyDataSetChanged(); pd.dismiss(); } public void goSearch(){ mTabHost.setCurrentTab(1); //separate thread for making http request and updating the arraylist Thread t = new Thread() { public void run() { searchResponse = sendSearchQuery(queryStr); try{ JSONArray results = searchResponse.getJSONArray("results"); //this is stupid. i probably have to see how to make a json adapter for(int index =0;index < results.length();index++){ JSONObject product = results.getJSONObject(index); //gets the searched products from the json object URL imgUrl = new URL(product.getString("image")); String productname = product.getString("productname"); String ptypename = product.getString("ptypename"); int pid = product.getInt("pid"); int positive = product.getInt("pos"); int negative = product.getInt("neg"); int neutral = product.getInt("neu"); SearchItem item = new SearchItem(imgUrl,productname,ptypename,neutral,positive,negative,pid); sResultsArr.add(item); } } catch(JSONException e){ } catch(Exception e){ } //returns back to UI therad h.post(mUpdateResults); } }; t.start(); } //sends a request with qry as URL //and receives back a JSONobject as response public JSONObject sendSearchQuery(String qry){ HttpRequest r = new HttpRequest(); JSONObject response = r.sendHttpRequest(qry); return response; } @Override public boolean onDown(MotionEvent arg0) { return gestureScanner.onTouchEvent(arg0); } @Override public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) { // TODO Auto-generated method stub return false; } @Override public void onLongPress(MotionEvent arg0) { // TODO Auto-generated method stub } @Override public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) { // TODO Auto-generated method stub return false; } @Override public void onShowPress(MotionEvent arg0) { // TODO Auto-generated method stub } @Override public boolean onSingleTapUp(MotionEvent arg0) { // TODO Auto-generated method stub return false; }

Ah, otra pregunta, si mi ListView tiene un onItemClickListener , ¿puede Android detectar entre un solo toque o hacer doble clic en él?


¿Por qué no estás usando una Pulsación larga? ¿O ya estás usando eso para otra cosa? Las ventajas de una pulsación larga sobre un doble toque:

  • Long Press es una interacción recomendada en las Pautas de UI, Double Touch no lo es.
  • Es lo que los usuarios esperan; un usuario puede no encontrar una acción de doble toque, ya que no irán a buscarla
  • Ya se maneja en la API .
  • La implementación de un toque doble afectará el manejo de toques individuales, ya que tendrá que esperar para ver si cada toque individual se convierte en un toque doble antes de poder procesarlo.

Código de dhruvi improvisado

public abstract class DoubleClickListener implements View.OnClickListener { private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds long lastClickTime = 0; boolean tap = true; @Override public void onClick(View v) { long clickTime = System.currentTimeMillis(); if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){ onDoubleClick(v); tap = false; } else tap = true; v.postDelayed(new Runnable() { @Override public void run() { if(tap) onSingleClick(); } },DOUBLE_CLICK_TIME_DELTA); lastClickTime = clickTime; } public abstract void onDoubleClick(View v); public abstract void onSingleClick(); }


Código equivalente de C # que utilicé para implementar la misma funcionalidad e incluso puedo personalizar para aceptar N número de Taps

public interface IOnTouchInterface { void ViewTapped(); } public class MultipleTouchGestureListener : Java.Lang.Object, View.IOnTouchListener { int clickCount = 0; long startTime; static long MAX_DURATION = 500; public int NumberOfTaps { get; set; } = 7; readonly IOnTouchInterface interfc; public MultipleTouchGestureListener(IOnTouchInterface tch) { this.interfc = tch; } public bool OnTouch(View v, MotionEvent e) { switch (e.Action) { case MotionEventActions.Down: clickCount++; if(clickCount == 1) startTime = Utility.CurrentTimeSince1970; break; case MotionEventActions.Up: var currentTime = Utility.CurrentTimeSince1970; long time = currentTime - startTime; if(time <= MAX_DURATION * NumberOfTaps) { if (clickCount == NumberOfTaps) { this.interfc.ViewTapped(); clickCount = 0; } } else { clickCount = 0; } break; } return true; } } public static class Utility { public static long CurrentTimeSince1970 { get { DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); DateTime dtNow = DateTime.Now; TimeSpan result = dtNow.Subtract(dt); long seconds = (long)result.TotalMilliseconds; return seconds; } } }

Actualmente, el código anterior acepta 7 como número de toques antes de que aparezca el evento View Tapped. Pero se puede personalizar con cualquier número


Como una alternativa ligera a GestureDetector puedes usar esta clase

public abstract class DoubleClickListener implements OnClickListener { private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds long lastClickTime = 0; @Override public void onClick(View v) { long clickTime = System.currentTimeMillis(); if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){ onDoubleClick(v); } else { onSingleClick(v); } lastClickTime = clickTime; } public abstract void onSingleClick(View v); public abstract void onDoubleClick(View v); }

Ejemplo:

view.setOnClickListener(new DoubleClickListener() { @Override public void onSingleClick(View v) { } @Override public void onDoubleClick(View v) { } });


Esta es mi solución, usa default setOnItemClickListener() . Tenía la misma tarea para implementar. Pronto publicaré ejemplos y clases personalizadas en mi github. Breve explicación es dada. No estoy seguro de si el tiempo en milisegundos es la diferencia correcta para el sistema (Ver fuente ViewConfiguration.getDoubleTapTimeout() ) para decidir entre toque simple y doble.

Editar: Véalo aquí: https://github.com/NikolaDespotoski/DoubleTapListView o https://github.com/NikolaDespotoski/DoubleTapListViewHandler


GuestureDetecter funciona bien en la mayoría de los dispositivos, me gustaría saber cómo el tiempo entre dos clics se puede personalizar en el evento de doble clic, no pude hacer eso. Actualicé el código anterior con "Bughi" "DoubleClickListner", agregué un temporizador que usa un controlador que ejecuta un código después de un retraso específico con un solo clic, y si se hace doble clic antes de esa demora, cancela el temporizador y solo hace clic y solo ejecuta hacer doble clic en la tarea. El código funciona bien Lo hace perfecto para utilizar como doble clickner:

private Timer timer = null; //at class level; private int DELAY = 500; view.setOnClickListener(new DoubleClickListener() { @Override public void onSingleClick(View v) { final Handler handler = new Handler(); final Runnable mRunnable = new Runnable() { public void run() { processSingleClickEvent(v); //Do what ever u want on single click } }; TimerTask timertask = new TimerTask() { @Override public void run() { handler.post(mRunnable); } }; timer = new Timer(); timer.schedule(timertask, DELAY); } @Override public void onDoubleClick(View v) { if(timer!=null) { timer.cancel(); //Cancels Running Tasks or Waiting Tasks. timer.purge(); //Frees Memory by erasing cancelled Tasks. } processDoubleClickEvent(v);//Do what ever u want on Double Click } });


Mi solución, puede ser útil.

long lastTouchUpTime = 0; boolean isDoubleClick = false; private void performDoubleClick() { long currentTime = System.currentTimeMillis(); if(!isDoubleClick && currentTime - lastTouchUpTime < DOUBLE_CLICK_TIME_INTERVAL) { isDoubleClick = true; lastTouchUpTime = currentTime; Toast.makeText(context, "double click", Toast.LENGTH_SHORT).show(); } else { lastTouchUpTime = currentTime; isDoubleClick = false; } }


Puedes usar GestureDetector. Vea el siguiente código:

public class MyView extends View { GestureDetector gestureDetector; public MyView(Context context, AttributeSet attrs) { super(context, attrs); // creating new gesture detector gestureDetector = new GestureDetector(context, new GestureListener()); } // skipping measure calculation and drawing // delegate the event to the gesture detector @Override public boolean onTouchEvent(MotionEvent e) { return gestureDetector.onTouchEvent(e); } private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } // event when double tap occurs @Override public boolean onDoubleTap(MotionEvent e) { float x = e.getX(); float y = e.getY(); Log.d("Double Tap", "Tapped at: (" + x + "," + y + ")"); return true; } } }

Puede anular otros métodos del oyente para obtener un solo toque, flinge, etc.


Realización solo y doble clic

public abstract class DoubleClickListener implements View.OnClickListener { private static final long DOUBLE_CLICK_TIME_DELTA = 200; private long lastClickTime = 0; private View view; private Handler handler = new Handler(); private Runnable runnable = new Runnable() { @Override public void run() { onSingleClick(view); } }; private void runTimer(){ handler.removeCallbacks(runnable); handler.postDelayed(runnable,DOUBLE_CLICK_TIME_DELTA); } @Override public void onClick(View view) { this.view = view; long clickTime = System.currentTimeMillis(); if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){ handler.removeCallbacks(runnable); lastClickTime = 0; onDoubleClick(view); } else { runTimer(); lastClickTime = clickTime; } } public abstract void onSingleClick(View v); public abstract void onDoubleClick(View v);

}


Solución de bughi y Jayant Arora para copypast:

public abstract class DoubleClickListener implements View.OnClickListener { private int position; private Timer timer; private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds long lastClickTime = 0; public DoubleClickListener (int position) { this.position = position; } @Override public void onClick(View v) { long clickTime = System.currentTimeMillis(); if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){ if (timer != null) { timer.cancel(); //Cancels Running Tasks or Waiting Tasks. timer.purge(); //Frees Memory by erasing cancelled Tasks. } onDoubleClick(v, position); } else { final Handler handler = new Handler(); final Runnable mRunnable = () -> { onSingleClick(v, position); }; TimerTask timertask = new TimerTask() { @Override public void run() { handler.post(mRunnable); } }; timer = new Timer(); timer.schedule(timertask, DOUBLE_CLICK_TIME_DELTA); } lastClickTime = clickTime; } public abstract void onSingleClick(View v, int position); public abstract void onDoubleClick(View v, int position);}


combinando el temporizador "Bughi" "DoubleClickListner" y "Jayant Arora" en una sola clase:

public abstract class DoubleClickListener implements OnClickListener { private Timer timer = null; //at class level; private int DELAY = 400; private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds long lastClickTime = 0; @Override public void onClick(View v) { long clickTime = System.currentTimeMillis(); if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){ processDoubleClickEvent(v); } else { processSingleClickEvent(v); } lastClickTime = clickTime; } public void processSingleClickEvent(final View v){ final Handler handler=new Handler(); final Runnable mRunnable=new Runnable(){ public void run(){ onSingleClick(v); //Do what ever u want on single click } }; TimerTask timertask=new TimerTask(){ @Override public void run(){ handler.post(mRunnable); } }; timer=new Timer(); timer.schedule(timertask,DELAY); } public void processDoubleClickEvent(View v){ if(timer!=null) { timer.cancel(); //Cancels Running Tasks or Waiting Tasks. timer.purge(); //Frees Memory by erasing cancelled Tasks. } onDoubleClick(v);//Do what ever u want on Double Click } public abstract void onSingleClick(View v); public abstract void onDoubleClick(View v); }

y se puede llamar como:

view.setOnClickListener(new DoubleClickListener() { @Override public void onSingleClick(View v) { } @Override public void onDoubleClick(View v) { } });


si no desea ir a la vista personalizada, puede usar el siguiente enfoque. por ejemplo, ImageView

// class level GestureDetector gestureDetector; boolean tapped; ImageView imageView; // inside onCreate of Activity or Fragment gestureDetector = new GestureDetector(context,new GestureListener());

// ------------------------------------------------ --------------------------------

public class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } // event when double tap occurs @Override public boolean onDoubleTap(MotionEvent e) { tapped = !tapped; if (tapped) { } else { } return true; } }

// ------------------------------------------------ --------------------------------

para ImageView

imageView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub return gestureDetector.onTouchEvent(event); } });


boolean nonDoubleClick = true, singleClick = false; private long firstClickTime = 0L; private final int DOUBLE_CLICK_TIMEOUT = 200; listview.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int pos, long id) { // TODO Auto-generated method stub Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub if (singleClick) { Toast.makeText(getApplicationContext(), "Single Tap Detected", Toast.LENGTH_SHORT).show(); } firstClickTime = 0L; nonDoubleClick = true; singleClick = false; } }, 200); if (firstClickTime == 0) { firstClickTime = SystemClock.elapsedRealtime(); nonDoubleClick = true; singleClick = true; } else { long deltaTime = SystemClock.elapsedRealtime() - firstClickTime; firstClickTime = 0; if (deltaTime < DOUBLE_CLICK_TIMEOUT) { nonDoubleClick = false; singleClick = false; Toast.makeText(getApplicationContext(), "Double Tap Detected", Toast.LENGTH_SHORT).show(); } } } });


public class MyView extends View { GestureDetector gestureDetector; public MyView(Context context, AttributeSet attrs) { super(context, attrs); // creating new gesture detector gestureDetector = new GestureDetector(context, new GestureListener()); } // skipping measure calculation and drawing // delegate the event to the gesture detector @Override public boolean onTouchEvent(MotionEvent e) { return gestureDetector.onTouchEvent(e); } private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } // event when double tap occurs @Override public boolean onDoubleTap(MotionEvent e) { float x = e.getX(); float y = e.getY(); Log.d("Double Tap", "Tapped at: (" + x + "," + y + ")"); return true; } } }