que - propiedades de texto en android studio
Android: ¿Detecta si el usuario toca y sale de la región de botones? (8)
Agregué un poco de registro en mi OnTouch y descubrí que MotionEvent.ACTION_CANCEL
estaba siendo golpeado. Eso es suficiente para mí ...
En Android, ¿cómo podemos detectar si un usuario toca el botón y sale de la región de este botón?
Aquí hay una View.OnTouchListener
que puede usar para ver si se envió MotionEvent.ACTION_UP
mientras el usuario tenía su dedo fuera de la vista:
private OnTouchListener mOnTouchListener = new View.OnTouchListener() {
private Rect rect;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (v == null) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
return true;
case MotionEvent.ACTION_UP:
if (rect != null
&& !rect.contains(v.getLeft() + (int) event.getX(),
v.getTop() + (int) event.getY())) {
// The motion event was outside of the view, handle this as a non-click event
return true;
}
// The view was clicked.
// TODO: do stuff
return true;
default:
return true;
}
}
};
La respuesta publicada por Entreco necesitaba un ligero ajuste en mi caso. Tuve que sustituirlo:
if(!rect.contains((int)event.getX(), (int)event.getY()))
para
if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY()))
porque event.getX()
y event.getY()
solo se aplican a ImageView, no a toda la pantalla.
Las dos respuestas principales están bien, excepto cuando la vista se encuentra dentro de una vista de desplazamiento: cuando se desplaza porque mueve el dedo, todavía se registra como un evento táctil pero no como un evento MotionEvent.ACTION_MOVE. Para mejorar la respuesta (que solo es necesaria si su vista está dentro de un elemento de desplazamiento):
private Rect rect; // Variable rect to hold the bounds of the view
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// Construct a rect of the view''s bounds
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if(rect != null && !rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
// User moved outside bounds
}
return false;
}
Probé esto en Android 4.3 y Android 4.4
No he notado ninguna diferencia entre la respuesta de Moritz y las 2 principales, pero esto también se aplica a su respuesta:
private Rect rect; // Variable rect to hold the bounds of the view
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// Construct a rect of the view''s bounds
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (rect != null){
v.getHitRect(rect);
if(rect.contains(
Math.round(v.getX() + event.getX()),
Math.round(v.getY() + event.getY()))) {
// inside
} else {
// outside
}
}
return false;
}
Si bien la respuesta de @FrostRocket es correcta, debe usar view.getX () e Y para tener en cuenta los cambios de traducción también:
view.getHitRect(viewRect);
if(viewRect.contains(
Math.round(view.getX() + event.getX()),
Math.round(view.getY() + event.getY()))) {
// inside
} else {
// outside
}
Tuve el mismo problema que el OP por el cual quería saber cuándo (1) se tocó una View
particular, así como (2) cuando se soltó el toque en la View
o (3) cuando el toque se movió fuera del límites de la View
. View.OnTouchListener
las diversas respuestas en este hilo para crear una extensión simple de View.OnTouchListener
(llamada SimpleTouchListener
) para que los demás no tengan que juguetear con el objeto MotionEvent
. La fuente de la clase se puede encontrar here o en la parte inferior de esta respuesta.
Para usar esta clase, simplemente View.setOnTouchListener(View.OnTouchListener)
como sigue el único parámetro del método View.setOnTouchListener(View.OnTouchListener)
:
myView.setOnTouchListener(new SimpleTouchListener() {
@Override
public void onDownTouchAction() {
// do something when the View is touched down
}
@Override
public void onUpTouchAction() {
// do something when the down touch is released on the View
}
@Override
public void onCancelTouchAction() {
// do something when the down touch is canceled
// (e.g. because the down touch moved outside the bounds of the View
}
});
Aquí está la fuente de la clase que puede agregar a su proyecto:
public abstract class SimpleTouchListener implements View.OnTouchListener {
/**
* Flag determining whether the down touch has stayed with the bounds of the view.
*/
private boolean touchStayedWithinViewBounds;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchStayedWithinViewBounds = true;
onDownTouchAction();
return true;
case MotionEvent.ACTION_UP:
if (touchStayedWithinViewBounds) {
onUpTouchAction();
}
return true;
case MotionEvent.ACTION_MOVE:
if (touchStayedWithinViewBounds
&& !isMotionEventInsideView(view, event)) {
onCancelTouchAction();
touchStayedWithinViewBounds = false;
}
return true;
case MotionEvent.ACTION_CANCEL:
onCancelTouchAction();
return true;
default:
return false;
}
}
/**
* Method which is called when the {@link View} is touched down.
*/
public abstract void onDownTouchAction();
/**
* Method which is called when the down touch is released on the {@link View}.
*/
public abstract void onUpTouchAction();
/**
* Method which is called when the down touch is canceled,
* e.g. because the down touch moved outside the bounds of the {@link View}.
*/
public abstract void onCancelTouchAction();
/**
* Determines whether the provided {@link MotionEvent} represents a touch event
* that occurred within the bounds of the provided {@link View}.
*
* @param view the {@link View} to which the {@link MotionEvent} has been dispatched.
* @param event the {@link MotionEvent} of interest.
* @return true iff the provided {@link MotionEvent} represents a touch event
* that occurred within the bounds of the provided {@link View}.
*/
private boolean isMotionEventInsideView(View view, MotionEvent event) {
Rect viewRect = new Rect(
view.getLeft(),
view.getTop(),
view.getRight(),
view.getBottom()
);
return viewRect.contains(
view.getLeft() + (int) event.getX(),
view.getTop() + (int) event.getY()
);
}
}
Compruebe MotionEvent.MOVE_OUTSIDE: Compruebe MotionEvent.MOVE:
private Rect rect; // Variable rect to hold the bounds of the view
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// Construct a rect of the view''s bounds
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
}
if(event.getAction() == MotionEvent.ACTION_MOVE){
if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
// User moved outside bounds
}
}
return false;
}
NOTA: si desea apuntar a Android 4.0, se abre todo un mundo de nuevas posibilidades: http://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
view.setClickable(true);
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!v.isPressed()) {
Log.e("onTouch", "Moved outside view!");
}
return false;
}
});
view.isPressed
utiliza view.pointInView
e incluye algunos touch slop. Si no desea slop, simplemente copie la lógica de la vista view.pointInView
(que es pública, pero está oculta, por lo que no forma parte de la API oficial y podría desaparecer en cualquier momento).
view.setClickable(true);
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
v.setTag(true);
} else {
boolean pointInView = event.getX() >= 0 && event.getY() >= 0
&& event.getX() < (getRight() - getLeft())
&& event.getY() < (getBottom() - getTop());
boolean eventInView = ((boolean) v.getTag()) && pointInView;
Log.e("onTouch", String.format("Dragging currently in view? %b", pointInView));
Log.e("onTouch", String.format("Dragging always in view? %b", eventInView));
v.setTag(eventInView);
}
return false;
}
});