Фрагмент над іншим фрагментом


271

Коли я показую один фрагмент (на весь екран з #77000000фоном) над іншим фрагментом (назвемо його головним), мій основний фрагмент все ще реагує на кліки (ми можемо натиснути кнопку, навіть якщо ми її не бачимо).

Питання : як запобігти клацанню на першому (головному) фрагменті?

EDIT

На жаль, я не можу просто приховати головний фрагмент, оскільки я використовую прозорий фон на другому фрагменті (так що користувач може бачити, що знаходиться позаду).


Виходячи з того, що ви дали нам працювати, ви повинні пробуйте встановити Visibilityз ваших , main Fragmentщоб , GONEколи ви його не використовуєте.
adneal

1
Не бачачи, як ви реалізуєте метод onClicked, я здогадуюсь, що ви повертаєтесь "помилково" при натисканні на нього.
DeeV

@DeeV, onClickметод нічого не повертає. Але ви даєте ідею, дякую (незабаром опублікую відповідь).
Дмитро Зайцев

1
D'oh. Ти маєш рацію. onTouch повертає його. Мені просто хочеться зрозуміти, чому сенсорний випадок потрапив через фрагмент. Це не повинно робити цього, якщо ви не видаєте сенсорні події.
DeeV

@DeeV, схоже, якщо ваше уявлення (яке, наприклад, над іншим) не вловлює подіюTouch, тоді система продовжує шукати інші представлення з тими ж координатами.
Дмитро Зайцев

Відповіді:


578

Встановіть clickableвластивість для подання другого фрагмента на істинне. Вид перегляне подію, щоб вона не була передана головному фрагменту. Отже, якщо подання другого фрагмента є макетом, це буде код:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true" />

4
Це працювало для мене. Здається, простіше, ніж рішення @Dmitry Zaitsev дало вище. Чи є якась причина, чому це було б поганою ідеєю? Я не можу ні про що думати, але просто хочу бути впевненим.
арієць

1
Це не спрацювало для мене. У мене є RelativeLayoutфрагмент всередині, і я встановив весь вид із clickeableвластивістю. Рішення @Dmitry вирішило мою проблему.
4gus71n

3
Це працювало для мене. "Клікабельний" в Android, мабуть, дещо схожий на iOS "" userInteractionEnabled "
mvds

17
Чому Android піддає нам жорсткі умови кодування ?!
Ло-Тан

1
У мене однакова проблема з ViewPager. Коли я прокручую першу сторінку, вона також переходить на другу сторінку, і це рішення не спрацювало для мене. Будь-які ідеї?
Гохан Арік

72

Рішення досить просте. У другому фрагменті (який перекриває наш основний фрагмент) нам просто потрібно зловити onTouchподію:

@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;
}

ваше рішення працювало +1 для цього, але чи можете ви сказати мені, чому нам це потрібно робити чітко?
Полювання

@Hunt вам не доведеться. Це просто інший спосіб зробити це (див. Прийняту відповідь)
Дмитро Зайцев

android: clickkable = "true" у головному макеті другого фрагмента xml.
Rishabh Srivastava

Виникає проблема з цим рішенням, коли ви переходите в режим зворотного зв'язку з доступністю, він не читає окремі елементи, а не отримує фокус на кореневому режимі.
Аміт Гарг

Версія Котліна: root.setOnTouchListener {_, _ -> true}
Гал Ром

21

Просто додайте clickable="true"і focusable="true"до батьківського макета

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

Якщо ви використовуєте AndroidX, спробуйте це

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

Це чимось відрізняється від прийнятої відповіді? focuseableнасправді не потрібно.
Дмитро Зайцев

2
Я думаю, що focusable="true"тут просто уникати попередження в Android Studio.
Артем М

9

Перший фрагмент слід приховати, коли ви показуєте другий фрагмент, якщо два фрагменти розміщені в одному поданні контейнера.

Якщо ви хочете дізнатися більше питань щодо вирішення проблем із фрагментом, ви можете побачити мою бібліотеку: https://github.com/JustKiddingBaby/FragmentRigger

FirstFragment firstfragment;
SecondFragment secondFragment;
FragmentManager fm;
FragmentTransaction ft=fm.beginTransaction();
ft.hide(firstfragment);
ft.show(secondFragment);
ft.commit();

1
Це має бути правильна відповідь! Спасибі, чоловіче. Я вирішив це питання в іншому проекті. Але я забув, як я це вирішив і, нарешті, я отримав вашу відповідь. Дякую.
Лікат Юлій

1
Я не думаю, що це правильне рішення. Фрагменти / Діяльність працюють у стеку перегляду. Вам доведеться зателефонувати. Show знову після того, як верхній фрагмент вискочить з стека, а значить, про нижній фрагмент потрібно повідомити, що верхній зник. Це просто додало додаткової логіки для підтримки.
XY

4

Вам потрібно додати android:focusable="true"сandroid:clickable="true"

Clickable означає, що на нього можна натискати вказівним пристроєм або натискати на нього сенсорним пристроєм.

Focusableозначає, що він може отримати фокус від такого пристрою введення, як клавіатура. Пристрої введення, такі як клавіатури, не можуть вирішити, якому виду надсилати свої події введення на основі самих входів, тому вони надсилають їх до подання, на якому є фокус.


2
and focusable = "true" потрібно уникати попередження в новій Android Studio
Hossam Hassan

2

Існує не одне рішення, що деякі з нас внесли свій внесок у цю нитку, але також я хотів би зазначити ще одне рішення. Якщо ви не хочете, щоб клацання та фокусування було рівним істинному корінню ViewGroup для кожного макета в XML, як я. Ви також можете розмістити його на своїй базі, якщо у вас є такий, як нижче;

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
    }

Ви також можете використовувати вбудову змінну, але я не вважав за краще це з моїх причин.

Я сподіваюся, що це допомагає тим, хто ненавидить компонування XML.


1

Прийнятна відповідь буде "спрацьовувати", але також спричинить продуктивність (перевитрата, повторне вимірювання зміни орієнтації), оскільки фрагмент внизу все ще малюється. Можливо, вам слід просто знайти фрагмент за тегом або ідентифікатором і встановити видимість у GONE або VISIBLE, коли вам потрібно знову показати.

У Котліні:

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

Це рішення є кращим перед альтернативою hide()та show()методами, FragmentTransactionколи ви використовуєте анімацію. Ви просто зателефонували йому з onTransitionStart()і onTransitionEnd()з Transition.TransitionListener.


1

Метод 1:

Ви можете додати до всіх фрагментів макет

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

Метод 2: (програмно)

Розгорніть увесь фрагмент FragmentBaseі т. Д. Потім додайте цей код доFragmentBase

@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);
}

0

Що ти можеш зробити - це ти можеш дати пустий клацання на макет попереднього фрагмента, використовуючи властивість onClick для батьківського макета цього головного фрагмента, і в діяльності ти можеш створити функцію doNothing(View view)і нічого не писати в ній. Це зробить це за вас.


0

Це звучить як випадок DialogFragment. Інакше за допомогою Менеджера фрагментів покладіть один на приховання, а другий на показ. Це працювало для мене.


0

Додавання android:clickable="true"не працювало для мене. Це рішення не працює на CoordinatorLayout, коли це батьківський макет. Ось чому я створив RelativeLayout як батьківський макет, додав android:clickable="true"до нього і розмістив CoordinatorLayout на цій RelativeLayout.


0

У мене було кілька фрагментів з одним xml.
Провівши години, я зняв, setPageTransformerі він почав працювати

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

Я мав шалену логіку.

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;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.