Android - Как отключить состояние STATE_HALF_EXPANDED нижнего листа

14

У меня есть нижний лист, который должен проходить между двумя состояниями, STATE_COLLAPSEDа STATE_EXPANDED когда он свернут, высота должна быть, 200dpа в развернутом виде она будет на весь экран.

Поэтому я устанавливаю BottomSheetBehaviorс

isFitToContents = false
peekHeight = 200dp

и я вынужден установить значение в halfExpandedRatioпротивном случае, когда на STATE_HALF_EXPANDEDнижнем листе займет половину экрана.

Я работаю с com.google.android.material:material:1.1.0-rc01

Есть ли способ отключить STATE_HALF_EXPANDEDсостояние?

Или я должен на самом деле установить skipCollapsed=true, выяснить с точки зрения соотношения, что означает 200dp и работать с STATE_HALF_EXPANDEDи STATE_EXPANDEDвместо STATE_COLLAPSEDиSTATE_EXPANDED

Ноа Драч
источник
пожалуйста, предоставьте более подробную информацию, например, как выглядит нижний лист.
UD ..
@ УД..Я не думаю, что содержание нижнего листа уместно в этом случае. Это более общий вопрос, можно ли отключить одно из состояний нижнего листа
Noa Drach
1
В моем случае использования кажется, что установка, halfExpandedRatio=0.25fа peekHeight = 200dpзатем обработка STATE_COLLAPSEDи STATE_HALF_EXPANDEDкак будто они в одном состоянии решают проблему. Держать вопрос открытым, если есть другие идеи.
Ноа Драч
Вы можете перейти
UD ..
Обязательно примите один из этих ответов, если он соответствует целям, изложенным в вашем вопросе!
CommonsWare

Ответы:

3

Значение половины расширили отношение к должно быть установлено до некоторого значения между 0 и 1 эксклюзивными , поэтому установите это значение в какое - то очень низкое число, которое наверняка будут меньше , чем ваши прятки высоты, скажем , «0.0001f». С этим значением вы даже не должны видеть STATE_HALF_EXPANDEDсостояние. Состояния будут колебаться между STATE_EXPANDEDи STATE_COLLAPSED.


Альтернативное решение

Приведенное выше решение работает и эффективно отключает STATE_HALF_EXPANDEDсостояние, но оно является хакерским (IMO) и может сломаться в будущем. Например, что, если будет применено разумное значение для половины расширенного отношения, которое находится где-то между высотой взгляда и полной высотой? Это было бы проблемой.

Требования, изложенные в OP, заключаются в том, что нижний лист должен переходить от высоты взгляда к полной высоте. С высотой взгляда проблем нет, но OP определяет, isFitToContents = falseкак добраться до полной высоты. (Я предполагаю, что его нижний лист может быть короче, чем доступное пространство.)

К сожалению, когда isFitToContents == falseвводится дополнительное «половинное» поведение, которое ОП хочет избежать, и поэтому возникает вопрос.

В дополнение к поведению "половинной высоты" вводится другое поведение, которое является "расширенным смещением". Расширенное смещение указывает, насколько далеко вниз от полноэкранного режима остановится нижний лист. Значение 100f, например, оставит 100pxграницу в верхней части нижнего листа при полном раскрытии. По умолчанию расширенное смещение равно нулю.

Я не знаю о каких-либо поведениях, которые isFitToContents == falseвводят, кроме упомянутых выше.

Итак, учитывая эти требования, можем ли мы сформировать нижний лист, который перемещается между высотой взгляда и полной высотой, одновременно определяя, isFitToContents == trueтаким образом, избегая проблемы «половинной высоты»? Не требуется ненулевое расширенное смещение, поэтому нам не нужно об этом беспокоиться.

Вот короткое демонстрационное приложение, демонстрирующее, что мы можем удовлетворить эти требования с правой структурой нижнего листа:

введите описание изображения здесь

MainActivity5.kt

class MainActivity5 : BaseActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_main5)  

        val bottomSheet = findViewById<LinearLayout>(R.id.bottom_sheet)  
        val sheetBehavior: BottomSheetBehavior<LinearLayout> = BottomSheetBehavior.from(bottomSheet)  
        sheetBehavior.isFitToContents = true // the default  
  sheetBehavior.peekHeight = 200  

  // Log the states the bottom sheet passes through.  
  sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {  
            override fun onStateChanged(bottomSheet: View, newState: Int) {  
                Log.d("MainActivity", "<<<< $newState = ${translateSheetState(newState)}")  
            }  

            override fun onSlide(bottomSheet: View, slideOffset: Float) {}  
        })  
    }  
}

BaseActivity.kt

open class BaseActivity : AppCompatActivity() {  

    protected fun translateSheetState(state: Int): String {  
        return when (state) {  
            BottomSheetBehavior.STATE_COLLAPSED -> "STATE_COLLAPSED"  
  BottomSheetBehavior.STATE_DRAGGING -> "STATE_DRAGGING"  
  BottomSheetBehavior.STATE_EXPANDED -> "STATE_EXPANDED"  
  BottomSheetBehavior.STATE_HALF_EXPANDED -> "STATE_HALF_EXPANDED"  
  BottomSheetBehavior.STATE_HIDDEN -> "STATE_HIDDEN"  
  BottomSheetBehavior.STATE_SETTLING -> "STATE_SETTLING"  
  else -> "Unknown state: $state"  
  }  
    }  
}

activity_main5.xml

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

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_orange_light"
        android:orientation="vertical"
        android:scrollbars="none"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="@string/short_text"
            android:textSize="16sp" />

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Если у нас длинный нижний лист, то для его прокрутки работает следующая структура:

activity_main6.xml

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

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_orange_light"
        android:orientation="vertical"
        android:scrollbars="none"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="16dp"
                android:text="@string/long_text"
                android:textSize="16sp" />
        </androidx.core.widget.NestedScrollView>
    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Cheticamp
источник
Что касается вашего первоначального ответа - я видел, что даже если я установил половину расширенного коэффициента, очень тонкий намек на нижнем листе все еще виден. И вообще, это не то поведение, которое я ищу. как вы упомянули в «Альтернативном решении» - «нижний лист должен переходить от высоты взгляда к полной высоте»
Ноа Драч
ваше «альтернативное решение», кажется, работает, и это решение, которое мне было нужно, мое первоначальное тестирование показало, что мне нужно использовать isFitToContents = false, но тестирование теперь isFitToContents = trueработает нормально
Noa Drach
@NoaDrach Если нижний лист скрыт, то в нижней части будет отображаться как минимум 1 пиксель из-за того, как рассчитывается смещение нижнего листа. Я не думал, что лист будет скрыт, но при показе 1px лист можно было просто скрыть, sheetBehavior.state = BottomSheetBehavior.STATE_HIDDENкогда достигнуто наполовину расширенное состояние, но это становится немного сложнее. Альтернативное решение лучше.
Четикамп
2

введите описание изображения здесь

Если вы хотите попробовать выше, как на картинке, вы можете следовать приведенному ниже коду, может это поможет вам !!!

public class CollectionsBottomSheet extends BottomSheetDialogFragment {
    private BottomSheetBehavior mBehavior;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
        View view = View.inflate(getContext(), R.layout.collections_layout, null);
        LinearLayout linearLayout = view.findViewById(R.id.root);
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();
        params.height = getScreenHeight();
        linearLayout.setLayoutParams(params);
        dialog.setContentView(view);
        mBehavior = BottomSheetBehavior.from((View) view.getParent());
        return dialog;

    }

    @Override
    public void onStart() {
        super.onStart();
        mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }

    public static int getScreenHeight() {
        return Resources.getSystem().getDisplayMetrics().heightPixels;
    }
}



xml 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:fitsSystemWindows="true">


    <LinearLayout
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/filter_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:drawableStart="@drawable/ic_cancel"
                android:drawableLeft="@drawable/ic_cancel"
                android:drawablePadding="30dp"
                android:gravity="center_vertical"
                android:padding="12dp"
                android:text="Filters"
                android:textColor="@color/black"
                android:textSize="18sp" />

            <View
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="1" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="10dp"
                android:layout_marginRight="10dp"
                android:padding="5dp"
                android:text="Reset ALL"
                android:textColor="#6f6f6f"
                android:textSize="12sp" />

        </LinearLayout>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#d8dbdb" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_star"
            android:drawableLeft="@drawable/ic_star"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="GUEST RATINGS"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_money"
            android:drawableLeft="@drawable/ic_money"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="PRICE RANGE"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_loan"
            android:drawableLeft="@drawable/ic_star"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="PAY AT HOTEL"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_folder"
            android:drawableLeft="@drawable/ic_folder"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="COLLECTIONS"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_perm_identity_black_24dp"
            android:drawableLeft="@drawable/ic_perm_identity_black_24dp"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="FACILITIES"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_apartment"
            android:drawableLeft="@drawable/ic_apartment"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="CATEGORIES"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_hotel_building"
            android:drawableLeft="@drawable/ic_hotel_building"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="ACCOMMODATION TYPE"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

    </LinearLayout>


</LinearLayout>
UD ..
источник
очень хороший ответ ... спас мой день
ответа
1

попробуйте установить a addBottomSheetCallbackна вашем устройстве BottomSheetBehavior, и когда вы обнаружите STATE_HALF_EXPANDEDсостояние, позвоните, setState(STATE_HIDDEN)чтобы всякий раз, когда нижний лист пытался достичь состояния на полпути, он просто закрывался.

Marmor
источник
Хорошая идея, в моем случае я бы установил состояние, STATE_COLLAPSEDа не STATE_HIDDEN. Но я попытался осуществить это, и переход от STATE_HALF_EXPANDEDк STATE_COLLAPSEDощущению неуклюже. Переход между состояниями анимирован, поэтому вы видите, что нижний лист останавливается, STATE_HALF_EXPANDEDа затем перемещается вSTATE_COLLAPSED
Noa Drach
Не могли бы вы объединить это с половинным коэффициентом 0?
Чудакулли
@Ridcully - здесь 2 проблемы - 1. halfExpandedRatio должен быть выше 0 2. установка его в очень низкое значение приведет к тому, что он будет свернут почти полностью (наполовину расширенное состояние), прежде чем он будет переведен в свернутое состояние. Я думал объединить это предложение с моим рабочим решением halfExpandedState=0.25f, так как переход между состояниями не будет таким очевидным. Но я не уверен, что это будет большим изменением по сравнению с тем, что у меня уже есть
Ноа Драч
1

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

<androidx.coordinatorlayout.widget.CoordinatorLayout 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/bottom_sheet_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/grey"
    android:clickable="true">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/rounded_bottom_sheet_background"
        android:orientation="vertical"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Мне пришлось изменить их динамически, поэтому я установил следующее на нижнем листе, но вы также можете сделать это в xml:

bottomSheet.setPeekHeight(200);// 200px
bottomSheet.setHideable(false);

Для исключения я добавил анимацию к своему фрагменту, используя следующую функцию:

fragmentTransaction.setCustomAnimations(
                    R.anim.fade_in,
                    R.anim.fade_out,
                    R.anim.fade_in,
                    R.anim.fade_out)

Надеюсь это поможет

Саурабх
источник
1

Попробуйте установить BottomSheetBehavior.setHalfExpandedRatio(0f). Существует не так много другого, что могло бы повлиять STATE_HALF_EXPANDED, если явно не установить состояние с помощью .setState () . Также должна быть возможность создать кастом Behavior, который расширяет CoordinatorLayout.Behavior<View>и не имеет STATE_HALF_EXPANDED. например. Перехватывать все с помощью CoordinatorLayout Behaviors .

Мартин Цайтлер
источник
0

Я пробовал разные способы, но ни одна техника не работала идеально. Я пытался перехватывать события BottomSheetBehavior.BottomSheetCallback {}и вызывать их dismiss()на основе пользовательской логики, но это вызвало рывок.

Итак, наконец, в моем BottomSheetDialogFragmentя добавил, bottomSheetBehavior.isDraggable = falseи это вызвало перетаскивание нижнего листа на ощупь А, я справился с закрытием диалога самостоятельно. в любом случае диалоговое окно пусто.

Обратите внимание, что нижний лист все еще расширяется с анимацией. Это действительно здорово!

переопределить веселье onCreateDialog (saveInstanceState: Bundle?): Dialog {val dialog = super.onCreateDialog (saveInstanceState)

    dialog.setOnShowListener {
        val bottomSheetDialog = it as BottomSheetDialog
        val bottomSheet =
            bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
                ?: return@setOnShowListener

        //Making background to transparent to avoid white background to given space margin.
        bottomSheet.setBackgroundColor(ContextCompat.getColor(context!!, R.color.transparent))

        val inflatedView = fragmentProfileDialogBinding.root
        val parent = inflatedView.parent as View

        val bottomSheetBehavior = BottomSheetBehavior.from(parent)
        bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
        bottomSheetBehavior.isDraggable = false
    }

    return dialog
}
Рахул Растоги
источник