Как разрешить внешнее касание для BottomSheetDialog?

Я работаю над BottomSheetDialogFragment, мое требование состоит в том, чтобы создать нижнее меню, где, если я нажимаю за пределами области фрагмента, оно должно не отменять диалоговое окно и должно сохраняться.

ПРОБЛЕМА: И событие за пределами фрагмента должно распространяться на представление/фрагмент нижнего фрагмента.

Я уже пробовал ниже (не работает для BottomDialogFragment): Разрешить внешнее касание для DialogFragment

Чтобы остановить отмену диалога, я попробовал ниже (я вызываю setCancelable(boolean) в onStart() BottomDialogFragment):

@Override
    public void setCancelable(boolean cancelable) {
        super.setCancelable(cancelable);

        BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
        dialog.setCanceledOnTouchOutside(cancelable);

        View bottomSheetView = dialog.getWindow().getDecorView().findViewById(R.id.design_bottom_sheet);
        BottomSheetBehavior.from(bottomSheetView).setHideable(cancelable);
    }

ссылка

РЕДАКТИРОВАТЬ: Нашел трудный путь, нет другого выхода, чем использование макета координат. Лучшее решение для BottomSheetDialog - здесь

  • Это решение решает проблему, но создает еще одну проблему. то есть все события actionMode не перемещаются, в то время как все другие события приложения.
  • И это мое лучшее решение проблемы

person Anmol    schedule 16.04.2019    source источник
comment
Помогает ли вам [эта ссылка][1]? [1]: medium.com/@betakuang/   -  person coroutineDispatcher    schedule 16.04.2019
comment
@StavroXhardha Я уже пробовал это, это позволяет мне остановить отмену диалога, но события также заблокированы для представлений ниже.   -  person Anmol    schedule 16.04.2019
comment
Я нашел решение и применил его в этом демонстрационном проекте github.com/andor201995/PersistIt.   -  person Anmol    schedule 04.11.2019


Ответы (5)


вы должны использовать android.support.design.widget.BottomSheetBehavior.

но если вы хотите иметь bottomSheet в другом классе, я предлагаю вам использовать Fragment и в этом fragment открыть свой bottomSheet

откройте свой фрагмент таким образом.

И в вашем фрагменте откройте свой bottomSheet в следующем коде:

in onInitViews

var mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheetCoordinatorLayout)
mBottomSheetBehavior!!.state = BottomSheetBehavior.STATE_HIDDEN

mBottomSheetBehavior!!.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
     override fun onStateChanged(bottomSheet: View, newState: Int) {
          when (newState) {
             BottomSheetBehavior.STATE_HIDDEN -> {
                  fragmentManager?.popBackStack()
             }
             //BottomSheetBehavior.STATE_COLLAPSED -> "Collapsed"
             //BottomSheetBehavior.STATE_DRAGGING -> "Dragging..."
             //BottomSheetBehavior.STATE_EXPANDED -> "Expanded"
             //BottomSheetBehavior.STATE_SETTLING -> "Settling..."
           }
      }

      override fun onSlide(bottomSheet: View, slideOffset: Float) {
          //text_view_state!!.text = "Sliding..."
      }
})

И ваш layout должен быть таким:

<android.support.design.widget.CoordinatorLayout 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:layoutDirection="ltr">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/bottomSheetCoordinatorLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:behavior_hideable="true"
        app:behavior_peekHeight="55dp"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/top_radius_primary_color"
            android:paddingStart="@dimen/material_size_32"
            android:paddingEnd="@dimen/material_size_32">

        </RelativeLayout>
    </android.support.design.widget.CoordinatorLayout>
</android.support.design.widget.CoordinatorLayout>

Я надеюсь, что это поможет вам

person mohsen    schedule 04.11.2019
comment
github.com/andor201995/PersistIt у него есть другие проблемы, если вы используете компонент навигации. Я могу' t использовать транзакцию фрагмента. Попробуйте этот демонстрационный проект для дальнейшего улучшения. Но объем этого вопроса это правильный ответ. - person Anmol; 04.11.2019

Попробуйте использовать код ниже в своем BottomSheetDialog:

 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
     return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply {
         setCanceledOnTouchOutside(false)
     }
 }

или оберните <CoordinatorLayout>, например, ваш <ConstraintLayout> и внедрите <layout /> и присоедините к BottomSheetBehavior.

person Yaroslav Ovdiienko    schedule 16.04.2019
comment
Привет, я пробовал это, но когда я щелкаю за пределами представления, диалоговое окно не отменяется, но в то же время блокируются все события, которые я хочу для более низкого представления. Я хочу знать, как заставить событие снизить представление. Спасибо за ответ. - person Anmol; 16.04.2019
comment
попробуй использовать не диалог. просто включите <layout /> и присоедините к BottomSheetBehavior, все будет нормально. - person Yaroslav Ovdiienko; 16.04.2019
comment
Для этого я думаю, что мне придется использовать макет координат как root, чтобы добавить BottomSheetBehavior как layout_behaviour. Но я просто пытался выяснить, могу ли я использовать диалог и обойти внешнюю область касания. - person Anmol; 16.04.2019
comment
хм, попробуйте отключить dim и применить в styles некоторые атрибуты. Возможно, будет полезно - person Yaroslav Ovdiienko; 17.04.2019
comment
Я думаю, вам просто нужно обернуть <CoordinatorLayout>, например, ваш <ConstraintLayout>, реализовать <layout /> и присоединить к BottomSheetBehavior. - person Yaroslav Ovdiienko; 17.04.2019
comment
@YaroslavOvdiienko спасибо за ваше предложение, оно работает именно так, как я хочу. Благодарю. - person Dharmishtha; 01.01.2021

Это невозможно, пока вы не используете BottomSheetDialogFragment. BottomSheetDialogFragment — это диалог, и как поведение каждого диалога, он не позволяет пользователю перехватывать любое представление за диалогом, хотя это видно пользователю.

Поэтому для этого вам нужно использовать Fragment вместо BottomSheetDialogFragment. И да, это потребует много изменений кода :) и вам придется жить без BottomSheetDialogFragment, если вы хотите перехватывать просмотры сзади.

person Pankaj Kumar    schedule 16.04.2019
comment
Основная проблема (с использованием фрагмента) заключается в том, что мое приложение/активность не использует Adjust resize, но в соответствии с требованием нижнее меню должно перемещаться вверх, если отображается клавиатура (пример). BottomSheetDialog сам по себе является интеллектуальным для настройки в соответствии с вызовом изменения размера системы. Я не в состоянии реализовать такое же поведение в MyCustomFragment. Поэтому я склонен использовать BottomSheetDialogFragment - person Anmol; 16.04.2019
comment
Я думаю, что если это единственная оставшаяся задача, то это выполнимо. Вам просто нужно спроектировать макет контейнера, как будто появляется клавиатура. вы можете посмотреть code.luasoftware.com/tutorials/android / или подобные темы - person Pankaj Kumar; 16.04.2019

Как сказал Панкадж Кумар, по умолчанию это невозможно. Тем не менее, я нашел обходной путь, который работает и позволяет касаниям просматривать изображения за пределами нижнего листа, оставляя нижний лист открытым.

Вы можете переопределить макет BottomSheetDialog следующим образом:

значения/refs.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <item name="design_bottom_sheet_dialog" type="layout" tools:override="true">@layout/custom_design_bottom_sheet_dialog</item>
</resources>

layout/custom_design_bottom_sheet_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ This is an override of the design_bottom_sheet_dialog from material library
-->
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

  <androidx.coordinatorlayout.widget.CoordinatorLayout
      android:id="@+id/coordinator"
      android:layout_width="match_parent"
      android:layout_height="wrap_content">

    <View
        android:id="@+id/touch_outside"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:visibility="gone"
        android:importantForAccessibility="no"
        android:soundEffectsEnabled="false"
        tools:ignore="UnusedAttribute"/>

    <FrameLayout
        android:id="@+id/design_bottom_sheet"
        style="?attr/bottomSheetStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal|top"
        app:layout_behavior="@string/bottom_sheet_behavior"/>

  </androidx.coordinatorlayout.widget.CoordinatorLayout>

</FrameLayout>

ВашCustomBottomSheetDialogFragment

override fun onStart() {
        super.onStart()

        // Set layout for custom bottom sheet by allowing background touches
        dialog?.window?.apply {
            setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
            setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
            
            attributes = attributes.apply {
                gravity = Gravity.BOTTOM
            }
            setDimAmount(0.0f)
        }
    }

При этом диалоговое окно имеет высоту wrap_content, а флаги позволяют обрабатывать касания представлениями за пределами этого диалогового окна.

person Sammekl    schedule 05.08.2020
comment
Ну наконец то! Что-то чистое и простое в использовании. Это отлично сработало для меня, я так счастлива, что могу поцеловать тебя :D! Спасибо!! - person Abushawish; 12.11.2020

попробуй это

setCanceledOnTouchOutside(false);
person 居然居    schedule 16.04.2019