Fragment nad innym problemem fragmentu

271

Kiedy pokazuję jeden fragment (pełny ekran z #77000000tłem) nad innym (nazwijmy go głównym), mój główny fragment nadal reaguje na kliknięcia (możemy kliknąć przycisk, nawet jeśli go nie widzimy).

Pytanie : jak zapobiec kliknięciom pierwszego (głównego) fragmentu?

EDYTOWAĆ

Niestety nie mogę po prostu ukryć głównego fragmentu, ponieważ używam przezroczystego tła na drugim fragmencie (więc użytkownik może zobaczyć, co znajduje się za).

Dmitrij Zajcew
źródło
Na podstawie tego, co nam dałeś do pracy, powinieneś spróbować ustawić Visibilityswój main Fragmentna, GONEkiedy go nie używasz.
adneal
1
Nie widząc, jak zaimplementujesz metodę onClicked, domyślam się, że po kliknięciu zwracasz „fałsz”.
DeeV
@DeeV, onClickmetoda nic nie zwraca. Ale dajesz pomysł, dzięki (wkrótce opublikuję odpowiedź).
Dmitrij Zajcew
1
Nie. Masz rację. onTouch zwraca go. Chciałbym tylko zrozumieć, dlaczego zdarzenie dotykowe spadło przez fragment. Nie powinno tak być, jeśli nie emitujesz zdarzeń dotykowych.
DeeV
@DeeV, wygląda na to, że jeśli twój widok (który, na przykład nad innymi) nie łapie zdarzenia onTouch, system kontynuuje wyszukiwanie innych widoków o tych samych współrzędnych.
Dmitrij Zajcew

Odpowiedzi:

578

Ustaw clickablewłaściwość w widoku drugiego fragmentu na wartość true. Widok uchwyci zdarzenie, aby nie zostało przekazane do głównego fragmentu. Więc jeśli widok drugiego fragmentu jest układem, byłby to kod:

<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
źródło
4
To zadziałało dla mnie. Wydaje się to łatwiejsze niż rozwiązanie podane przez @Dmitry Zaitsev. Czy jest jakiś powód, dla którego byłby to zły pomysł? Wydaje mi się, że nie mogę o tym myśleć, ale chcę tylko mieć pewność.
przybywa
1
To mi nie zadziałało. Mam RelativeLayoutwnętrze fragmentu i ustawiam cały widok za pomocą clickeablewłaściwości. Rozwiązanie @Dmitry rozwiązuje mój problem.
4gus71n
3
To zadziałało dla mnie. „klikalne” w Androidzie najwyraźniej przypomina nieco „
UserInteractionEnabled
17
Dlaczego Android poddaje nas trudnym warunkom kodowania ?!
Lo-Tan,
1
Mam ten sam problem z ViewPager. Kiedy przewijam pierwszą stronę, przechodzi ona również na drugą stronę, a to rozwiązanie nie działało dla mnie. Jakieś pomysły?
Gokhan Arik,
72

Rozwiązanie jest dość proste. W naszym drugim fragmencie (który pokrywa się z naszym głównym fragmentem) musimy po prostu złapać onTouchzdarzenie:

@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;
}
Dmitrij Zajcew
źródło
Twoje rozwiązanie działało +1, ale czy możesz mi powiedzieć, dlaczego musimy to zrobić jawnie?
Poluj
@Hunt, nie musisz. To tylko kolejny sposób, aby to zrobić (patrz zaakceptowana odpowiedź)
Dmitrij Zajcew
android: clickable = "true" w głównym układzie xml drugiego fragmentu.
Rishabh Srivastava
Występuje problem z tym rozwiązaniem, gdy przejdziesz do trybu rozmowy o ułatwieniach dostępu WŁĄCZONY, nie odczytuje on poszczególnych elementów, a zamiast tego koncentruje się na widoku głównym.
Amit Garg
Wersja Kotlin: root.setOnTouchListener {_, _ -> true}
Gal Rom
21

Wystarczy dodać clickable="true"i focusable="true"do układu nadrzędnego

 <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>

Jeśli używasz AndroidX, spróbuj tego

 <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
źródło
Czy to w jakiś sposób różni się od przyjętej odpowiedzi? focuseablenie jest tak naprawdę konieczne.
Dmitrij Zajcew
2
Myślę, że focusable="true"tutaj jest tylko po to, aby uniknąć ostrzeżenia w Android Studio.
Artem M
9

Powinieneś ukryć pierwszy fragment, gdy wyświetlasz drugi fragment, jeśli dwa fragmenty są umieszczone w tym samym widoku pojemnika.

Jeśli chcesz dowiedzieć się więcej pytań na temat rozwiązywania problemów dotyczących Fragmentu, możesz zobaczyć moją bibliotekę: https://github.com/JustKiddingBaby/FragmentRigger

FirstFragment firstfragment;
SecondFragment secondFragment;
FragmentManager fm;
FragmentTransaction ft=fm.beginTransaction();
ft.hide(firstfragment);
ft.show(secondFragment);
ft.commit();
JingYeoh
źródło
1
To powinna być właściwa odpowiedź! Dziękuje. Rozwiązałem to pytanie w innym projekcie. Ale zapomniałem, jak to rozwiązałem i wreszcie otrzymałem twoją odpowiedź. Dziękuję Ci.
Licat Julius
1
Nie sądzę, żeby to było właściwe rozwiązanie. Fragmenty / działania działają na stosie widoków. Będziesz musiał ponownie wywołać .show po usunięciu górnego fragmentu ze stosu, co oznacza, że ​​dolny fragment musi zostać poinformowany o zniknięciu górnego fragmentu. To tylko dodatkowa logika do utrzymania.
XY
4

Musisz dodać za android:focusable="true"pomocąandroid:clickable="true"

Clickable oznacza, że ​​można go kliknąć wskaźnikiem lub dotknąć urządzeniem dotykowym.

Focusableoznacza, że ​​może uzyskać ostrość z urządzenia wejściowego, takiego jak klawiatura. Urządzenia wejściowe, takie jak klawiatury, nie mogą decydować, do którego widoku mają wysyłać zdarzenia wejściowe na podstawie samych danych wejściowych, więc wysyłają je do widoku, który jest aktywny.

Hossam Hassan
źródło
2
i focusable = „true” jest wymagane, aby uniknąć ostrzeżenia w nowym Android Studio
Hossam Hassan
2

Jest więcej niż jedno rozwiązanie, które niektórzy z nas przyczynili się do tego wątku, ale chciałbym też wspomnieć o innym rozwiązaniu. Jeśli nie masz ochoty umieszczać klikalnego i możliwego do skupienia, równego wierności z głównym układem każdego układu, ViewGroup w XML takim jak ja. Możesz także umieścić go w swojej bazie, jeśli masz taką jak poniżej;

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
    }

Możesz także użyć zmiennej wbudowanej, ale nie wolałem jej z moich powodów.

Mam nadzieję, że pomoże to tym, którzy nie znoszą plików XML układu.

Yekta Sarıoğlu
źródło
1

Dopuszczalna odpowiedź „zadziała”, ale spowoduje również koszty wydajności (przesadzenie, ponowny pomiar przy zmianie orientacji), ponieważ fragment na dole jest nadal rysowany. Być może powinieneś po prostu znaleźć fragment według tagu lub identyfikatora i ustawić widoczność na BRAK lub WIDOCZNIE, gdy chcesz ponownie wyświetlić.

W Kotlinie:

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

To rozwiązanie jest lepsze niż alternatywa hide()i show()metody FragmentTransactionkorzystania z animacji. Po prostu nazywaj to od onTransitionStart()and onTransitionEnd()of Transition.TransitionListener.

Allan Veloso
źródło
1

Metod 1:

Możesz dodać do układu wszystkich fragmentów

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

Metod 2: (programowo)

Rozszerz cały fragment z FragmentBaseitd. Następnie dodaj ten kod doFragmentBase

@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);
}
MarsPeople
źródło
0

Możesz tylko kliknąć puste miejsce w układzie poprzedniego fragmentu, używając właściwości onClick do układu nadrzędnego tego głównego fragmentu, aw działaniu możesz utworzyć funkcję doNothing(View view)i nic w niej nie pisać. To zrobi to za ciebie.

Satish Silveri
źródło
0

To brzmi jak skrzynka dla DialogFragment. W przeciwnym razie przy pomocy Fragment Managera jeden z nich ukryje, a drugi pokaże. To zadziałało dla mnie.

Juan Mendez
źródło
0

Dodanie android:clickable="true"nie działało dla mnie. To rozwiązanie nie działa w CoordinatorLayout, gdy jest to układ nadrzędny. Właśnie dlatego utworzyłem RelativeLayout jako układ nadrzędny, dodałem android:clickable="true"do niego i umieściłem CoordinatorLayout na tym RelativeLayout.

Zhebzhik Babich
źródło
0

Miałem wiele fragmentów z tym samym xml.
Po spędzeniu godzin usunąłem setPageTransformeri zaczęło działać

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

Miałem logikę oszustwa.

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
źródło