Android - jak wyłączyć stan STATE_HALF_EXPANDED dolnego arkusza

14

Mam dolny arkusz, który powinien przechodzić między 2 stanami, STATE_COLLAPSEDa STATE_EXPANDED kiedy jest zwinięty, wysokość powinna być, 200dpa po rozwinięciu będzie pełny ekran.

Więc ja ustawienie BottomSheetBehaviorz

isFitToContents = false
peekHeight = 200dp

i jestem zmuszony ustawić inną wartość, halfExpandedRatiogdy na STATE_HALF_EXPANDEDdolnym arkuszu zajmie połowę ekranu.

Pracuję w / com.google.android.material:material:1.1.0-rc01

Czy istnieje sposób na wyłączenie STATE_HALF_EXPANDEDstanu?

Albo powinienem właściwie ustawić skipCollapsed=true, dowiedzieć się, co to znaczy 200dp, i pracować z STATE_HALF_EXPANDEDi STATE_EXPANDEDzamiast STATE_COLLAPSEDiSTATE_EXPANDED

Noa Drach
źródło
podaj więcej szczegółów, takich jak wygląd dolnego arkusza.
UD ..
@ UD .. Nie sądzę, aby zawartość dolnego arkusza była w tym przypadku istotna. To jest bardziej ogólne pytanie, czy można wyłączyć jeden ze stanów dolnego arkusza
Noa Drach
1
W moim przypadku użycia wydaje się, że ustawienie, halfExpandedRatio=0.25fa peekHeight = 200dpnastępnie traktowanie STATE_COLLAPSEDi STATE_HALF_EXPANDEDjakby były w tym samym stanie rozwiązuje problem. Pozostawienie pytania otwartego na wypadek, gdyby pojawiły się inne pomysły.
Noa Drach,
możesz skorzystać z tego linku, pomoże to androidhive.info/2017/12/android-working-with-bottom-sheet
UD ..
Należy zaakceptować jedną z tych odpowiedzi, jeśli spełnia ona cele określone w pytaniu!
CommonsWare

Odpowiedzi:

3

Wartość pół rozwiniętego współczynnika musi być ustawiona na pewną wartość między 0 a 1 wyłączną , więc ustaw tę wartość na bardzo małą liczbę, która z pewnością będzie mniejsza niż wysokość podglądu, powiedz „0.0001f”. Przy tej wartości nie powinieneś nawet widzieć STATE_HALF_EXPANDEDstanu. Stany będą się zmieniać między STATE_EXPANDEDi STATE_COLLAPSED.


Alternatywne rozwiązanie

Powyższe rozwiązanie działa i skutecznie wyłącza STATE_HALF_EXPANDEDstan, ale jest hackerskie (IMO) i może się złamać w przyszłości. Na przykład co się stanie, jeśli zostanie wymuszona rozsądna wartość dla połowy rozszerzonego stosunku, który jest gdzieś pomiędzy wysokością podglądu a pełną wysokością? To byłby problem.

Wymagania określone w PO są następujące: dolny arkusz powinien przechodzić między wysokością podglądu a pełną wysokością. Nie ma problemu z wysokością podglądu, ale OP określa, isFitToContents = falseaby dostać się na pełną wysokość. (Zakładam, że jego dolny arkusz może być krótszy niż dostępne miejsce).

Niestety, gdy isFitToContents == falsewprowadza się dodatkowe zachowanie „na pół wysokości”, którego PO chce uniknąć, a zatem pytanie.

Oprócz zachowania „połowy wysokości” wprowadza się inne zachowanie, które jest „rozszerzonym przesunięciem”. Rozszerzone przesunięcie określa, jak daleko od pełnego ekranu zatrzyma się dolny arkusz. Na przykład wartość 100f, 100pxpo pełnym rozwinięciu , pozostawi ramkę na górze dolnego arkusza. Wartość domyślna dla rozszerzonego przesunięcia wynosi zero.

Nie jestem świadomy żadnych zachowań, które isFitToContents == falsewprowadzają inne niż wymienione powyżej.

Zatem biorąc pod uwagę te wymagania, czy możemy zaprojektować dolny arkusz, który porusza się między wysokością rzutu a pełną wysokością, jednocześnie określając w isFitToContents == trueten sposób uniknięcie problemu „połowy wysokości”? Nie ma wymagania dla niezerowego rozszerzonego przesunięcia, więc nie musimy się tym martwić.

Oto krótka aplikacja demonstracyjna pokazująca, że ​​możemy spełnić te wymagania dzięki odpowiedniej strukturze dolnego arkusza:

wprowadź opis zdjęcia tutaj

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>

Jeśli mamy długi dolny arkusz, wówczas do przewijania działa następująca struktura:

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
źródło
jeśli chodzi o twoją początkową odpowiedź - widziałem, że nawet jeśli ustawię połowę współczynnika powiększenia, nadal widać bardzo cienką wskazówkę dolnego arkusza. Zresztą nie tego szukam. jak wspomniałeś w „Alternatywnym rozwiązaniu” - „dolny arkusz powinien przechodzić między wysokością podglądu a pełną wysokością”
Noa Drach
Twoje „alternatywne rozwiązanie” wydaje się działać i jest to rozwiązanie, którego potrzebowałem, moje pierwsze testy wykazały, że muszę użyć isFitToContents = false, ale teraz testowanie isFitToContents = truedziała / działa dobrze
Noa Drach
@NoaDrach Jeśli dolny arkusz można ukryć, na dole będzie co najmniej 1 piksel ze względu na sposób obliczania przesunięcia dolnego arkusza. Nie myślałem, że arkusz zostanie ukryty, ale przy pokazaniu 1 piksela arkusz można po prostu zmusić do ukrycia, sheetBehavior.state = BottomSheetBehavior.STATE_HIDDENgdy zostanie osiągnięty stan połowy rozwiniętej, ale to staje się trochę skomplikowane. Alternatywne rozwiązanie jest lepsze.
Cheticamp
2

wprowadź opis zdjęcia tutaj

jeśli chcesz spróbować powyżej jak na obrazku, możesz wykonać poniższy kod, niech ci to pomoże !!!

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 ..
źródło
bardzo dobra odpowiedź ... uratował mi dzień
unownsp
1

spróbuj ustawić addBottomSheetCallbackna swoim BottomSheetBehavior, a kiedy wykryjesz STATE_HALF_EXPANDEDstan, zadzwoń, setState(STATE_HIDDEN)więc za każdym razem, gdy dolny arkusz próbuje osiągnąć stan w połowie, po prostu się zamknie.

marmor
źródło
fajny pomysł, w moim przypadku ustawiłbym stan na STATE_COLLAPSEDi nie STATE_HIDDEN. Ale starałem się go i przejście od wdrożenia STATE_HALF_EXPANDEDdo STATE_COLLAPSEDczuje się niezgrabne. Przejście między stanami jest animowane, więc widać, że dolny arkusz zatrzymuje się, STATE_HALF_EXPANDEDa następnie przesuwa się doSTATE_COLLAPSED
Noa Drach
Czy możesz to połączyć z wartością HalfExpandedRatio wynoszącą 0?
Ridcully,
@Ridcully - tutaj 2 problemy - 1. połowaRozwiniętaRatio musi być powyżej 0 2. ustawienie jej na bardzo niską wartość spowoduje, że zminimalizuję ją prawie całkowicie (stan pół rozwinięty), zanim zostanie przyciągnięty do stanu zwiniętego. Myślałem o połączeniu tej sugestii z moim działającym rozwiązaniem halfExpandedState=0.25f, b / c, wtedy przejście między stanami nie będzie tak oczywiste. Ale nie jestem pewien, czy będzie to duża zmiana w porównaniu z tym, co już mam
Noa Drach
1

Miałem podobny przypadek użycia, w którym układ musiał wynosić jedną trzecią wysokości. Próbowałem następujących i działało świetnie.

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

Musiałem to zmienić dynamicznie, więc ustawiłem poniższe w dolnym arkuszu, ale możesz to również zrobić w xml:

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

W celu odrzucenia dodałem animację do mojego fragmentu za pomocą następującej funkcji:

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

Mam nadzieję że to pomoże

Saurabh
źródło
0

Próbowałem na różne sposoby, ale żadna technika nie działała idealnie. Próbowałem przechwytywać zdarzenia BottomSheetBehavior.BottomSheetCallback {}i wywoływać je dismiss()na podstawie niestandardowej logiki, ale spowodowało to szarpnięcie.

Nareszcie BottomSheetDialogFragmentdodałem, bottomSheetBehavior.isDraggable = falsea to spowodowało Przeciągnięcie dolnej kartki przez dotyk I sam poradziłem sobie z zamknięciem okna dialogowego. w oknie dialogowym pustego obszaru i tak zostaną odrzucone.

Pamiętaj, że dolny arkusz nadal się rozwija z animacją. To naprawdę świetne!

przesłonić zabawę 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
}
Rahul Rastogi
źródło