para - manual de programacion android pdf
Android hace que la vista desaparezca haciendo clic fuera de ella (9)
Tengo algunas vistas que hago visibles al presionar un botón. Quiero que desaparezcan si hago clic fuera de esas vistas.
¿Cómo se haría esto en Android?
Además, me doy cuenta de que el "botón de retroceso" también puede ayudar a los usuarios de Android con esto (podría usarlo como una forma secundaria de cerrar las vistas), pero algunas de las tabletas ya ni siquiera usan un botón de retroceso "físico". ha sido muy desestimado.
Encuentre el rectángulo de vista y luego detecte si el evento de clic está fuera de la vista.
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Rect viewRect = new Rect();
mTooltip.getGlobalVisibleRect(viewRect);
if (!viewRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
setVisibility(View.GONE);
}
return true;
}
Si desea utilizar el evento táctil en otro lugar, pruebe
return super.dispatchTouchEvent(ev);
Esta es una pregunta antigua, pero pensé que daría una respuesta que no está basada en eventos onTouch
. Como lo sugirió RedLeader, también es posible lograr esto utilizando eventos de enfoque. Tuve un caso en el que necesitaba mostrar y ocultar un grupo de botones organizados en una ventana emergente personalizada, es decir, los botones estaban todos ubicados en el mismo ViewGroup
. Algunas cosas que debes hacer para que esto funcione:
El grupo de vistas que desea ocultar debe tener
View.setFocusableInTouchMode(true)
. Esto también se puede configurar en XML usandoandroid:focusableintouchmode
.La raíz de su vista, es decir, la raíz de su diseño completo, probablemente algún tipo de diseño lineal o relativo, también debe poder enfocarse según el # 1 anterior
Cuando se muestra el grupo de vista, llame a
View.requestFocus()
para enfocarlo.Su grupo de vistas debe anular
View.onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect)
o implementar su propioOnFocusChangeListener
y usarView.setOnFocusChangeListener()
Cuando el usuario toca fuera de su vista, el enfoque se transfiere a la raíz de la vista (ya que la configura como enfocable en el # 2) o a otra vista que es
EditText
inherente (EditText
o similar)Cuando detecta la pérdida de enfoque utilizando uno de los métodos en el n.º 4, sabe que el enfoque se ha transferido a algo fuera de su grupo de visualización y puede ocultarlo.
Supongo que esta solución no funciona en todos los escenarios, pero funcionó en mi caso específico y parece que también podría funcionar para el OP.
He creado ViewGroup personalizado para mostrar el cuadro de información anclado a otra vista (globo emergente). La vista del niño es un cuadro de información real, BalloonView está en pantalla completa para la posición absoluta del niño y el toque de intercepción.
public BalloonView(View anchor, View child) {
super(anchor.getContext());
//calculate popup position relative to anchor and do stuff
init(...);
//receive child via constructor, or inflate/create default one
this.child = child;
//this.child = inflate(...);
//this.child = new SomeView(anchor.getContext());
addView(child);
//this way I don''t need to create intermediate ViewGroup to hold my View
//but it is fullscreen (good for dialogs and absolute positioning)
//if you need relative positioning, see @iturki answer above
((ViewGroup) anchor.getRootView()).addView(this);
}
private void dismiss() {
((ViewGroup) getParent()).removeView(this);
}
Manejar clics dentro del niño:
child.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//write your code here to handle clicks inside
}
});
Para descartar mi vista, haga clic fuera SIN delegar el toque a la vista subyacente:
BalloonView.this.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
Para descartar mi vista, haga clic fuera de CON delegar el toque a la vista subyacente:
@Override
public boolean onTouchEvent(MotionEvent event) {
dismiss();
return false; //allows underlying View to handle touch
}
Para descartar el botón Atrás presionado:
//do this in constructor to be able to intercept key
setFocusableInTouchMode(true);
requestFocus();
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
dismiss();
return true;
}
return super.onKeyPreIme(keyCode, event);
}
He estado buscando una manera de cerrar mi vista cuando toco afuera y ninguno de estos métodos satisface mis necesidades realmente. Encontré una solución y la publicaré aquí en caso de que alguien esté interesado.
Tengo una actividad base que prácticamente todas mis actividades se extienden. En ella tengo:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (myViewIsVisible()){
closeMyView();
return true;
}
return super.dispatchTouchEvent(ev);
}
Entonces, si mi vista es visible, simplemente se cerrará, y si no, se comportará como un evento táctil normal. No estoy seguro si es la mejor manera de hacerlo, pero parece funcionar para mí.
Implementar onTouchListener()
. Compruebe que las coordenadas del toque están fuera de las coordenadas de su vista.
Probablemente haya algún tipo de manera de hacerlo con onFocus()
, etc. - Pero no lo sé.
Necesitaba la habilidad específica para no solo eliminar una vista al hacer clic fuera de ella, sino también permitir que el clic pase a la actividad normalmente. Por ejemplo, tengo un diseño separado, notification_bar.xml, que necesito para inflar y agregar dinámicamente a cualquier actividad actual cuando sea necesario.
Si creo una vista superpuesta del tamaño de la pantalla para recibir cualquier clic fuera de la vista notification_bar y elimino ambas vistas con un clic, la vista principal (la vista principal de la actividad) aún no ha recibido ningún clic, lo que significa que cuando la barra de notificación está visible, se requieren dos clics para hacer clic en un botón (uno para descartar la vista de barra de notificación y otro para hacer clic en el botón).
Para resolver esto, puede crear su propio DismissViewGroup que amplíe ViewGroup y anule el siguiente método:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
ViewParent parent = getParent();
if(parent != null && parent instanceof ViewGroup) {
((ViewGroup) parent).removeView(this);
}
return super.onInterceptTouchEvent(ev);
}
Y luego su vista agregada dinámicamente se verá un poco como:
<com.example.DismissViewGroup android:id="@+id/touch_interceptor_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent" ...
<LinearLayout android:id="@+id/notification_bar_view" ...
Esto le permitirá interactuar con la vista y, en el momento en que haga clic fuera de la vista, descartará la vista e interactuará normalmente con la actividad.
Una manera fácil / estúpida:
Cree una vista vacía ficticia (digamos ImageView sin fuente), hágala llenar padre
Si se hace clic, haz lo que quieras hacer.
Debe tener la etiqueta raíz en su archivo XML para ser un RelativeLayout. Contendrá dos elementos: su vista ficticia (establezca su posición para align the Parent Top
). La otra es tu vista original que contiene las vistas y el botón (esta vista podría ser un LinearLayout o lo que sea que hagas. No olvides establecer su posición para align the Parent Top
).
Espero que esto te ayude, buena suerte!
gracias a @ituki por la idea
FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80000000"
android:clickable="true">
<LinearLayout
android:clickable="true" // not trigger
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FFF"
android:orientation="vertical"
android:padding="20dp">
...............
</LinearLayout>
</FrameLayout>
y el código java
mContainer = (View) view.findViewById(R.id.search_container);
mContainer.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
Log.d("aaaaa", "outsite");
return true;
}
return false;
}
});
Es trabajo cuando se toca fuera de LinearLayout.
respuesta basada en Kai Wang: sugiero que primero verifique la visibilidad de su vista, que se base en mi escenario cuando el usuario haga clic en fab myView sea visible y luego cuando el usuario haga clic fuera de myView desaparezca
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Rect viewRect = new Rect();
myView.getGlobalVisibleRect(viewRect);
if (myView.getVisibility() == View.VISIBLE && !viewRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
goneAnim(myView);
return true;
}
return super.dispatchTouchEvent(ev);
}