Contexte
Je suis chargé de créer une interface utilisateur qui se comporte de la même manière que Google Maps affiche une feuille de fond pour un résultat trouvé.
Il comporte trois phases différentes:
- Contenu inférieur. La zone supérieure est toujours palpable et ne fera pas défiler quoi que ce soit en bas
- Contenu plein écran, tandis que la zone supérieure a un grand en-tête.
- Contenu plein écran, tandis que la zone supérieure n'a que la barre d'outils.
Voici ce dont je parle sur Google Maps:
Le problème
Le fait est que la feuille du bas ne fait pas encore partie de la bibliothèque de conception (bien que cela ait été demandé, ici ).
Non seulement cela, mais l'interface utilisateur semble assez complexe et nécessite une gestion de la barre d'outils sur plusieurs phases.
Ce que j'ai essayé
J'ai trouvé une bonne (assez) bibliothèque pour la feuille du bas ( ici ), et ajouté du contenu à son échantillon de fragment, pour avoir à peu près les mêmes vues que celles indiquées sur les échantillons de conception de matériaux (comme ici ), pour avoir un CollapsingToolbarLayout qui prendra soin des phases 2 + 3.
Dans l'application que je crée, je dois aussi déplacer une icône pendant que vous faites défiler, mais je pense que si je réussis avec le reste, cela devrait être facile. Voici le code:
fragment_my.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
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.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="24dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Info"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Friends"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Related"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
android:clickable="true"
android:src="@android:drawable/ic_menu_send"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>
MyFragment.java
public class MyFragment extends BottomSheetFragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_my, container, false);
view.setMinimumHeight(getResources().getDisplayMetrics().heightPixels);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) view.findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("AAA");
final Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
final AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavUtils.navigateUpFromSameTask(getActivity());
}
});
final ImageView imageView = (ImageView) view.findViewById(R.id.backdrop);
Glide.with(this).load(R.drawable.cheese_1).centerCrop().into(imageView);
return view;
}
}
BottomSheetFragmentActivity.java
public final class BottomSheetFragmentActivity extends AppCompatActivity {
protected BottomSheetLayout bottomSheetLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom_sheet_fragment);
bottomSheetLayout = (BottomSheetLayout) findViewById(R.id.bottomsheet);
findViewById(R.id.bottomsheet_fragment_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyFragment().show(getSupportFragmentManager(), R.id.bottomsheet);
}
});
bottomSheetLayout.setShouldDimContentView(false);
bottomSheetLayout.setPeekOnDismiss(true);
bottomSheetLayout.setPeekSheetTranslation(200);
bottomSheetLayout.setInterceptContentTouch(false);
bottomSheetLayout.setDefaultViewTransformer(new BaseViewTransformer() {
@Override
public void transformView(final float translation, final float maxTranslation, final float peekedTranslation, final BottomSheetLayout parent, final View view) {
Log.d("AppLog", "translation:" + translation + " maxTranslation:" + maxTranslation + " peekedTranslation:" + peekedTranslation);
}
});
}
}
Cela fonctionne presque bien. Le seul problème est le passage du n ° 3 au n ° 2:
La question
Quel est le problème avec le code? Que puis-je faire pour obtenir le comportement requis?
la source
CoordinatorLayout
sur le 2ème écran?Réponses:
Remarque : lisez les modifications en bas
OK, j'ai trouvé un moyen de le faire, mais j'ai dû changer le code de plusieurs classes, afin que la feuille du bas connaisse l'état de l'appBarLayout (développé ou non), et ignore le défilement au cas où il serait non développé:
BottomSheetLayout.java
Champs ajoutés:
init () - a ajouté ceci:
Ajout d'une fonction pour définir l'appBarLayout:
onDetachedFromWindow () - a ajouté ceci:
onTouchEvent () - a ajouté ceci:
Ce sont les principaux changements. Maintenant pour ce qui les définit:
MyFragment.java
onCreateView () - a ajouté ceci:
J'ai également ajouté cette fonction:
Voici maintenant comment l'activité informe le fragment sur appBarLayout:
Le projet est maintenant disponible sur GitHub:
https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet
J'espère qu'il n'y a pas de bugs.
La solution a malheureusement des bugs, donc je ne marquerai pas cette réponse comme la bonne:
Si quelqu'un peut vous aider, faites-le.
Pour le problème n ° 1, j'ai essayé d'ajouter un correctif en définissant la visibilité sur INVISIBLE lorsque la feuille du bas n'est pas encore consultée, mais cela ne fonctionne pas toujours, surtout si un clavier est affiché.
Pour le problème n ° 1, j'ai trouvé comment le résoudre, en enveloppant simplement (dans "fragment_my.xml") le CoordinatorLayout avec n'importe quelle vue que vous souhaitez utiliser (j'ai utilisé FrameLayout), et en mettant également une vue en taille réelle dans it (je viens de mettre "View"), comme tel:
Cela a probablement confondu le bottomSheet quand j'avais le CoordinatorLayout étant sa vue. J'ai mis à jour le projet, mais s'il y a un moyen d'avoir une meilleure solution, j'aimerais en savoir plus.
Ces derniers mois, Google a publié sa propre classe bottomSheet, mais comme je l'ai découvert, elle a beaucoup de problèmes, donc je ne peux même pas l'essayer.
la source
GRANDE MISE À JOUR
Parce qu'il y avait comme 4 ou 5 questions sur le même sujet, MAIS avec des exigences DIFFÉRENTES, et j'ai essayé de répondre à toutes, mais un administrateur non poli les a supprimées / fermées, me faisant créer un ticket pour chacune et les changer en éviter le «copier-coller» Je vous laisse un lien vers la réponse complète dans laquelle vous pouvez trouver toutes les explications sur la façon d'obtenir un comportement complet comme Google Maps.
Répondre à votre question
Avec la bibliothèque de support 23.x.x +, vous pouvez le faire en modifiant la valeur par défaut
BottomSheetBehavior
, en ajoutant une autre statistique avec les étapes suivantes:CoordinatorLayout.Behavior<V>
BottomSheetBehavior
fichier par défaut vers votre nouveau.Modifiez la méthode
clampViewPositionVertical
avec le code suivant:Ajouter un nouvel état:
Modifier les méthodes suivantes:
onLayoutChild
,onStopNestedScroll
,BottomSheetBehavior<V> from(V view)
etsetState
( en option)Je vais ajouter ces méthodes modifiées et un lien vers l'exemple de projet .
Et voici à quoi ça ressemble:
la source
CoordinatorLayout
inactivity_main.xml
. Je suppose que vous avez une bonne expérience avec la mise en page du coordinateur, sinon jetez un œil à ce lien que j'ai trouvéAvez-vous essayé cela? http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 Ici, il est dit que nous pouvons simplement spécifier un comportement de mise en page de la feuille inférieure.
METTRE À JOUR:
Fondamentalement, le lien indique:
En attachant un BottomSheetBehavior à une vue enfant d'un CoordinatorLayout (c'est-à-dire en ajoutant app: layout_behavior = "android.support.design.widget.BottomSheetBehavior"), vous obtiendrez automatiquement la détection tactile appropriée pour effectuer la transition entre cinq états:
Si vous souhaitez recevoir des rappels de changements d'état, vous pouvez ajouter un BottomSheetCallback:
Alors que BottomSheetBehavior capture le cas persistant de la feuille inférieure, cette version fournit également un BottomSheetDialog et BottomSheetDialogFragment pour remplir le cas d'utilisation des feuilles inférieures modales. Remplacez simplement AppCompatDialog ou AppCompatDialogFragment par leurs équivalents de feuille inférieure pour que votre boîte de dialogue soit conçue comme une feuille inférieure.
la source
J'ai également dû implémenter une vue similaire à la façon dont Google Maps affiche une feuille de fond pour un résultat trouvé.
Voici à quoi ressemble le mien:
Au début, j'ai défini une feuille de fond avec un en-tête et un contenu défilable, mais layout_height ne semblait pas envelopper le contenu ni de l'en-tête ni du contenu défilable malgré la spécification
wrap_content
.Ce problème a disparu lorsque j'ai utilisé
LinearLayout
au lieu deConstraintLayout
pour laCoordinatorLayout
disposition enfant de (et pour ses enfants).activity_main.xml
MainActivity.java
app / build.gradle
la source