Android - Comment désactiver l'état STATE_HALF_EXPANDED d'une feuille inférieure

14

J'ai une feuille inférieure qui devrait aller entre 2 états, STATE_COLLAPSEDet STATE_EXPANDED lorsqu'elle est effondrée, la hauteur doit être 200dpet lorsqu'elle est développée, elle sera en plein écran.

Donc , je suis la mise BottomSheetBehavioren

isFitToContents = false
peekHeight = 200dp

et je suis obligé de définir une valeur dans le halfExpandedRatiocas contraire lorsque STATE_HALF_EXPANDEDla feuille du bas prendra la moitié de l'écran.

Je travaille avec com.google.android.material:material:1.1.0-rc01

Existe-t-il un moyen de désactiver l' STATE_HALF_EXPANDEDétat?

Ou je devrais en fait définir skipCollapsed=true, comprendre en termes de ratio ce que 200dp signifie et travailler avec STATE_HALF_EXPANDEDet STATE_EXPANDEDau lieu de STATE_COLLAPSEDetSTATE_EXPANDED

Noa Drach
la source
veuillez fournir plus de détails tels que l'apparence de la feuille inférieure.
UD ..
@ UD..Je ne pense pas que le contenu de la feuille du bas soit pertinent dans ce cas. Ceci est une question plus générale, est-il possible de désactiver l'un des états de la feuille inférieure
Noa Drach
1
Pour mon cas d'utilisation, il semble que la définition halfExpandedRatio=0.25f, peekHeight = 200dppuis le traitement STATE_COLLAPSEDet STATE_HALF_EXPANDEDcomme s'ils étaient le même état résout le problème. Garder la question ouverte au cas où il y aurait d'autres idées.
Noa Drach
vous pouvez suivre ce lien, il vous aidera androidhive.info/2017/12/android-working-with-bottom-sheet
UD ..
Assurez-vous d'accepter l'une de ces réponses, si l'on atteint les objectifs énoncés dans votre question!
CommonsWare

Réponses:

3

La valeur du rapport semi-étendu doit être définie sur une valeur comprise entre 0 et 1 exclusif , alors définissez cette valeur sur un nombre très bas qui est certain d'être inférieur à votre hauteur de vue, par exemple "0,0001f". Avec cette valeur, vous ne devriez même pas voir l' STATE_HALF_EXPANDEDétat. Les états fluctueront entre STATE_EXPANDEDet STATE_COLLAPSED.


Solution alternative

La solution ci-dessus fonctionne et désactive efficacement l' STATE_HALF_EXPANDEDétat, mais elle est hackish (IMO) et peut se casser à l'avenir. Par exemple, que se passe-t-il si une valeur raisonnable pour le rapport semi-étendu qui se situe quelque part entre la hauteur de coup d'œil et la hauteur totale est appliquée? Ce serait un problème.

Les exigences énoncées par l'OP sont que la feuille inférieure doit faire la transition entre la hauteur de coup d'œil et la hauteur totale. Il n'y a pas de problème avec la hauteur de coup d'œil, mais l'OP spécifie isFitToContents = falsed'atteindre la pleine hauteur. (Je suppose que sa feuille inférieure peut être plus courte que l'espace disponible.)

Malheureusement, lorsqu'un isFitToContents == falsecomportement supplémentaire "à mi-hauteur" est introduit que l'OP veut éviter et donc la question.

En plus du comportement "demi-hauteur", un autre comportement est introduit qui est le "décalage étendu". Le décalage étendu spécifie à quelle distance en bas du plein écran la feuille inférieure s'arrêtera. Une valeur de 100f, par exemple, laissera une 100pxbordure en haut de la feuille inférieure lorsqu'elle sera entièrement développée. La valeur par défaut pour le décalage étendu est zéro.

Je ne suis au courant d'aucun comportement isFitToContents == falseintroduisant autre que ceux mentionnés ci-dessus.

Donc, étant donné ces exigences, pouvons-nous façonner une feuille de fond qui se déplace entre la hauteur de coup d'œil et la pleine hauteur tout en spécifiant isFitToContents == trueévitant ainsi le problème de la "demi-hauteur"? Il n'y a aucune exigence pour un décalage étendu non nul, nous n'avons donc pas à nous en soucier.

Voici une courte application de démonstration démontrant que nous pouvons répondre à ces exigences avec la structure de feuille inférieure droite:

entrez la description de l'image ici

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>

Si nous avons une longue feuille de fond, la structure suivante fonctionne pour la faire défiler:

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
la source
en ce qui concerne votre réponse initiale - j'ai vu que même si je définissais un rapport à moitié étendu, un soupçon très mince de la feuille inférieure était toujours visible. Et de toute façon, ce n'est pas le comportement que je recherche. comme vous l'avez mentionné dans "Solution alternative" - ​​"la feuille inférieure doit faire la transition entre la hauteur de l'aperçu et la hauteur totale"
Noa Drach
votre "solution alternative" semble fonctionner et c'est la solution dont j'avais besoin, mes tests initiaux ont montré que je devais utiliser isFitToContents = false, mais les tests maintenant isFitToContents = truefonctionnent correctement
Noa Drach
@NoaDrach Si la feuille inférieure est masquable, il y aurait au moins 1 px affiché en bas en raison de la façon dont le décalage de la feuille inférieure est calculé. Je ne pensais pas que la feuille serait cachée mais, avec 1px affiché, la feuille pourrait simplement être forcée d'être cachée sheetBehavior.state = BottomSheetBehavior.STATE_HIDDENlorsque l'état semi-développé est atteint, mais cela devient un peu compliqué. La solution alternative est meilleure.
Cheticamp
2

entrez la description de l'image ici

si vous voulez essayer ci-dessus comme dans l'image, vous pouvez suivre le code ci-dessous, que cela vous aide !!!

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 ..
la source
très bonne réponse ... sauvé ma journée
unownsp
1

essayez de définir un addBottomSheetCallbacksur votre BottomSheetBehavior, et lorsque vous détectez un STATE_HALF_EXPANDEDétat, appelez setState(STATE_HIDDEN)donc chaque fois que la feuille inférieure essaie d'atteindre l'état à mi-chemin, elle se fermera.

marmor
la source
bonne idée, dans mon cas, je définirais l'état STATE_COLLAPSEDet non STATE_HIDDEN. Mais j'ai essayé de le mettre en œuvre et la transition de STATE_HALF_EXPANDEDà STATE_COLLAPSEDse sent maladroite. La transition entre les états est animée, vous voyez donc la feuille du bas s'arrêter à STATE_HALF_EXPANDEDpuis elle se déplace versSTATE_COLLAPSED
Noa Drach
Pourriez-vous combiner cela avec une demi-extension de 0?
Ridcully
@Ridcully - 2 problèmes ici - 1. halfExpandedRatio doit être supérieur à 0 2. le définir sur une valeur très faible me le réduira presque complètement (état semi-développé), avant d'être accroché à l'état réduit. J'ai pensé à combiner cette suggestion avec ma solution de travail halfExpandedState=0.25f, b / c, puis la transition entre les États ne sera pas aussi évidente. Mais, je ne suis pas sûr que ce sera un grand changement par rapport à ce que j'ai déjà
Noa Drach
1

J'ai eu un cas d'utilisation similaire où la disposition devait être un tiers de la hauteur. J'ai essayé ce qui suit et cela a très bien fonctionné.

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

J'ai dû les modifier dynamiquement, j'ai donc défini ce qui suit sur la feuille inférieure, mais vous pouvez également le faire en xml:

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

Pour le rejet, j'ai ajouté une animation à mon fragment en utilisant la fonction suivante:

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

J'espère que cela t'aides

Saurabh
la source
0

J'ai essayé différentes manières, mais aucune technique ne fonctionnait parfaitement. J'ai essayé d'intercepter des événements BottomSheetBehavior.BottomSheetCallback {}et j'ai appelé en dismiss()fonction d'une logique personnalisée, mais cela a provoqué une secousse.

Donc, enfin, dans mon BottomSheetDialogFragmentj'ai ajouté bottomSheetBehavior.isDraggable = falseet cela a provoqué le glissement de la feuille inférieure au toucher Et, j'ai géré le rejet de la boîte de dialogue par moi-même. sur la boîte de dialogue de zone vide de toute façon être rejeté.

Notez que la feuille inférieure se développe toujours avec une animation. C'est vraiment génial!

remplacer le plaisir onCreateDialog (SavedInstanceState: Bundle?): Dialogue {val dialog = super.onCreateDialog (SavedInstanceState)

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