Fragmento sobre otro problema de fragmentos

271

Cuando muestro un fragmento (que es pantalla completa con #77000000fondo) sobre otro fragmento (llamémoslo principal), mi fragmento principal aún reacciona a los clics (podemos hacer clic en un botón incluso si no lo vemos).

Pregunta : ¿cómo evitar los clics en el primer fragmento (principal)?

EDITAR

Desafortunadamente, no puedo ocultar el fragmento principal, porque estoy usando un fondo transparente en el segundo fragmento (por lo tanto, el usuario puede ver qué se encuentra detrás).

Dmitry Zaytsev
fuente
Sobre la base de lo que nos ha dado para trabajar, usted debe tratar de establecer el Visibilityde tu main Fragmenta GONEcuando no lo esté utilizando.
adneal
1
Sin ver cómo implementa su método onClicked, supongo que está devolviendo "falso" al hacer clic.
DeeV
@DeeV, el onClickmétodo no devuelve nada. Pero da una idea, gracias (publicaré la respuesta pronto).
Dmitry Zaytsev
1
D'oh Tienes razón. onTouch lo devuelve. Solo desearía entender por qué un evento táctil cayó a través de un fragmento. No debería hacer eso si no está emitiendo eventos táctiles.
DeeV
@DeeV, parece que si su vista (que, por ejemplo, encima de otra) no capta el evento Touch, entonces el sistema continúa buscando otras vistas con las mismas coordenadas.
Dmitry Zaytsev

Respuestas:

578

Establezca la clickablepropiedad en la vista del segundo fragmento como verdadera. La vista capturará el evento para que no se pase al fragmento principal. Entonces, si la vista del segundo fragmento es un diseño, este sería el código:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true" />
Jure Vizjak
fuente
44
Esto funcionó para mí. Parece más fácil que la solución que @Dmitry Zaitsev dio anteriormente. ¿Hay alguna razón por la cual sería una mala idea? Parece que no puedo pensar en ninguno, pero solo quiero estar seguro.
Ariets
1
Esto no funcionó para mí. Tengo un RelativeLayoutfragmento dentro y configuro toda la vista con la clickeablepropiedad. La solución de @Dmitry resuelve mi problema.
4gus71n el
3
Esto funcionó para mí. "hacer clic" en Android aparentemente es algo así como iOS "userInteractionEnabled"
mvds
17
¿Por qué Android nos somete a duras condiciones de codificación?
Lo-Tan
1
Tengo el mismo problema con ViewPager. Cuando me desplazo en la primera página, también pasa a la segunda página, y esta solución no me funcionó. ¿Algunas ideas?
Gokhan Arik
72

La solución es bastante simple. En nuestro segundo fragmento (que se superpone a nuestro fragmento principal) solo necesitamos capturar el onTouchevento:

@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstance){
    View root = somehowCreateView();

    /*here is an implementation*/

    root.setOnTouchListener(new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            return true;
        }
    });
    return root;
}
Dmitry Zaytsev
fuente
su solución funcionó +1 para eso, pero ¿puede decirme por qué necesitamos hacer esto explícitamente?
Caza el
@Hunt no tienes que hacerlo. Esa es solo otra forma de hacerlo (ver respuesta aceptada)
Dmitry Zaytsev
android: clickable = "true" en el diseño principal xml de su segundo fragmento.
Rishabh Srivastava
Hay un problema con esta solución, cuando activa el modo talkback de accesibilidad, no leerá los elementos individuales sino que enfocará la vista raíz.
Amit Garg
Versión de Kotlin: root.setOnTouchListener {_, _ -> true}
Gal Rom
21

Simplemente agregue clickable="true"y focusable="true"al diseño principal

 <android.support.constraint.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:clickable="true"
      android:focusable="true">

      <!--Your views-->

 </android.support.constraint.ConstraintLayout>

Si está utilizando AndroidX, intente esto

 <androidx.constraintlayout.widget.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:clickable="true"
      android:focusable="true">

          <!--Your views-->

 </androidx.constraintlayout.widget.ConstraintLayout>
Miravzal
fuente
¿Es esto de alguna manera diferente de la respuesta aceptada? focuseableNo es realmente necesario.
Dmitry Zaytsev
2
Creo que focusable="true"aquí es solo para evitar una advertencia en Android Studio.
Artem M
9

Debe ocultar el primer fragmento cuando muestre el segundo Fragmento si se colocan dos fragmentos en la misma vista de contenedor.

Si desea saber más preguntas sobre cómo resolver problemas sobre Fragment, puede ver mi biblioteca: https://github.com/JustKiddingBaby/FragmentRigger

FirstFragment firstfragment;
SecondFragment secondFragment;
FragmentManager fm;
FragmentTransaction ft=fm.beginTransaction();
ft.hide(firstfragment);
ft.show(secondFragment);
ft.commit();
JingYeoh
fuente
1
¡Esta debería ser la respuesta correcta! Gracias hombre. He resuelto esta pregunta en otro proyecto. Pero he olvidado cómo lo resolví y finalmente, obtuve tu respuesta. Gracias.
Licat Julius
1
No creo que esta sea la solución correcta. Los fragmentos / actividades funcionan en una pila de vistas. Tendrá que llamar a .show nuevamente después de que el fragmento superior salga de la pila, lo que significa que el fragmento inferior debe ser informado de que el superior se ha ido. Solo se agrega lógica adicional para mantener.
XY
4

Necesitas agregar android:focusable="true"conandroid:clickable="true"

Clickable significa que un dispositivo puntero puede hacer clic en él o un dispositivo táctil.

Focusablesignifica que puede obtener el foco de un dispositivo de entrada como un teclado. Los dispositivos de entrada como los teclados no pueden decidir a qué vista enviar sus eventos de entrada en función de las entradas mismas, por lo que los envían a la vista que tiene el foco.

Hossam Hassan
fuente
2
y focusable = "true" es necesario para evitar una advertencia en el nuevo Android Studio
Hossam Hassan
2

Hay más de una solución que algunos de nosotros contribuimos a este hilo, pero también me gustaría mencionar otra solución. Si no le gusta, hacer clic y enfocar es igual a True ViewGroup raíz de cada diseño en XML como yo. También puede ponerlo en su base si tiene uno como el siguiente;

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ) : View? {
        super.onCreateView(inflater, container, savedInstanceState)

        val rootView = inflater.inflate(layout, container, false).apply {
            isClickable = true
            isFocusable = true
        }

        return rootView
    }

También puede usar la variable en línea, pero no la preferí por mis motivos.

Espero que sea útil para los que odian los XML de diseño.

Yekta Sarıoğlu
fuente
1

La respuesta aceptable "funcionará", pero también causará un costo de rendimiento (sobregiro, volver a medir el cambio de orientación) ya que el fragmento en la parte inferior todavía se está dibujando. Tal vez debería simplemente encontrar el fragmento por etiqueta o ID y establecer la visibilidad en GONE o VISIBLE cuando necesite mostrar de nuevo.

En Kotlin:

fragmentManager.findFragmentByTag(BottomFragment.TAG).view.visibility = GONE

Esta solución es preferible a la alternativa hide()y los show()métodos de FragmentTransactioncuando utiliza animaciones. Que acaba de llamar desde el onTransitionStart()y onTransitionEnd()de Transition.TransitionListener.

Allan Veloso
fuente
1

Método 1:

Puede agregar a todos los fragmentos de diseño

android:clickable="true"
android:focusable="true"
android:background="@color/windowBackground"

Método 2: (mediante programación)

Extienda todos los fragmentos de FragmentBaseetc. Luego agregue este código aFragmentBase

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    getView().setBackgroundColor(getResources().getColor(R.color.windowBackground));
    getView().setClickable(true);
    getView().setFocusable(true);
}
MartePersonas
fuente
0

Lo que puede hacer es dar un clic en blanco al diseño del fragmento anterior utilizando la propiedad onClick para el diseño principal de ese fragmento principal y, en la actividad, puede crear una función doNothing(View view)y no escribir nada en él. Esto lo hará por ti.

Satish Silveri
fuente
0

Esto suena como un caso para DialogFragment. De lo contrario, con Fragment Manager, confirme uno para ocultar y el otro para mostrar. Eso ha funcionado para mi.

Juan Mendez
fuente
0

La adición de android:clickable="true"no funcionó para mí. Esta solución no funciona en CoordinatorLayout cuando es un diseño primario. Es por eso que hice RelativeLayout como diseño principal, lo agregué android:clickable="true"y coloqué CoordinatorLayout en este RelativeLayout.

Zhebzhik Babich
fuente
0

Tenía múltiples fragmentos con el mismo xml.
Después de pasar horas, me quité setPageTransformery comenzó a funcionar

   //  viewpager.setPageTransformer(false, new BackgPageTransformer())

Tenía una lógica de escalamiento.

public class BackgPageTransformer extends BaseTransformer {

    private static final float MIN_SCALE = 0.75f;

    @Override
    protected void onTransform(View view, float position) {
        //view.setScaleX Y
    }

    @Override
    protected boolean isPagingEnabled() {
        return true;
    }
}
AskQ
fuente