web-dev-qa-db-fra.com

Android CollapsingToolbarLayout avec vue personnalisée

Je suis l'exemple du projet Cheesesquare pour comprendre la nouvelle bibliothèque de matériaux de conception.

Je me demande s'il existe un moyen d'utiliser une vue personnalisée (comme Telegram) avec ImageView, titre et sous-titre au lieu du simple titre fourni par le widget CollapsingToolbarLayout.

Merci.

24
CeccoCQ

J'ai eu le même problème et j'ai passé plusieurs heures à essayer de trouver une solution. Ma solution a été d'ajouter les vues réduites (ImageView et TextView) à l'intérieur de CollapsingToolbarLayout, puis de gérer la transition dans le code. De cette façon, il est plus flexible et plus simple que d'étendre à partir de CollapsingToolbarLayout.

Vous devez d'abord ajouter vos vues à l'intérieur de CollapsingToolbarLayout avec les propriétés de parallaxe:

        <ImageView
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:paddingTop:"80dp"
            Android:src="@drawable/icon"
            app:layout_collapseMode="parallax"
            app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here

Ensuite, définissez la mise à l'échelle des vues à l'aide d'un OnOffsetchangeListner:

  private static final float SCALE_MINIMUM=0.5f;
  appBarLayout.setOnWorkingOffsetChange(new  ControllableAppBarLayout.OnWorkingOffsetChange() {
        @Override
        public void onOffsetChange(int offSet, float collapseDistance) {
            imageView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
            imageView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));

            textView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
            textView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));

            // You can also setTransitionY/X, setAlpha, setColor etc.
        }
    });

D'une manière ou d'une autre, le offsetChangedListener par défaut ne fonctionnait pas correctement pour moi (vous devriez probablement toujours l'essayer avec l'écouteur par défaut en premier), j'ai donc utilisé le ControllableAppBarLayout de https: // Gist .github.com/blipinsk/3f8fb37209de6d3eea99 et a ajouté ce qui suit:

private OnWorkingOffsetChange onWorkingOffsetChange;

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
    if (!isInEditMode()) {
        onWorkingOffsetChange.onOffsetChange(i, (float) i / appBarLayout.getTotalScrollRange());
    }
}

public void setOnWorkingOffsetChange(OnWorkingOffsetChange listener) {
    this.onWorkingOffsetChange = listener;
}

public interface OnWorkingOffsetChange {
    void onOffsetChange(int offSet, float collapseDistance);
}

Le seul problème est que vous devez définir app:contentScrim="#00000000" (transparent) pour votre CollapsingToolbarLayout, donc vos vues sont toujours visibles lorsque la barre d'outils est réduite. Si vous avez vraiment besoin de l'effet d'effondrement de l'arrière-plan, je suis sûr que vous pouvez le "simuler" en définissant l'alpha d'une ImageView d'arrière-plan dans le OffsetChangeListener. ;)

20
Ciron

Depuis le widget lui-même, il ne semble pas y avoir de moyen d'activer cela directement, comme il était possible d'ajouter des vues personnalisées à la barre d'outils.

Ce que vous pourriez essayer de faire cependant, c'est d'ouvrir la source du CollapsingToolbarLayout.class et découvrez comment le CollapsingTextHelper.class est utilisé pour définir le titre. Vous pouvez essayer de créer votre propre widget en étendant le CollapsingToolbarLayout.

Ces liens peuvent vous aider à créer des composants/vues personnalisés, si vous ne les avez pas créés auparavant: Vues personnalisées , Composants personnalisés

Je n'ai pas encore essayé cela, mais c'est en fait quelque chose que je pensais essayer d'obtenir une solution similaire à celle que vous recherchez. Les étapes que je suivrais jusqu'à présent:

  1. Créez des attributs personnalisés pour les paramètres de sous-titres dans attrs.xml
  2. Créez votre propre MyCollapsingToolbarLayout en étendant l'original.
  3. Assurez-vous d'appeler super dans les constructeurs, afin que le composant d'origine reste intact.
  4. Créez un subtitleTextHelper en ajoutant un nouveau CollapsingTextHelper à votre composant.
  5. Remplacez onDraw pour dessiner réellement votre sous-titre.
  6. Mettez à jour la mise en page contenant votre CollapingsToolbarLayout avec vos attributs de sous-titre (style par défaut et autres, peut-être un texte de sous-titre fixe).
  7. Appliquez les modifications dans le Activity contenant votre CollapsingToolbar. (Convertissez CollapsingToolbarlayout en MyCollapingsToolbarLayout, définissez les sous-titres, les paramètres personnalisés supplémentaires, etc.).
  8. Croisez les doigts, testez.

Je vais y jeter un œil maintenant.

2
StingRay5

Je vais modifier légèrement la réponse de Christopher pour montrer comment vous pouvez faire en sorte que votre vue personnalisée ne disparaisse pas lors de l'effondrement:

Vous devez d'abord ajouter vos vues à l'intérieur de CollapsingToolbarLayout avec les propriétés de parallaxe:

        <ImageView
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:paddingTop:"80dp"
            Android:src="@drawable/icon"
            app:layout_collapseMode="parallax"
            app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here

Ajoutez plutôt la vue personnalisée par programme et elle ne disparaîtra pas lors de l'effondrement. Par exemple, voici une vue qui contient un titre et un sous-titre:

    final FrameLayout frameLayout = new FrameLayout(mActivity);
    FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT);
    frameLayout.setLayoutParams(frameLayoutParams);


    // Create new LinearLayout
    final LinearLayout linearLayout = new LinearLayout(mActivity);
    frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
    frameLayoutParams.gravity = Gravity.BOTTOM;
    linearLayout.setLayoutParams(frameLayoutParams);
    linearLayout.setOrientation(LinearLayout.VERTICAL);


    // Add textviews
    final TextView textView1 = new TextView(mActivity);
    LinearLayout.LayoutParams linearLayoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT);
    frameLayoutParams.gravity = Gravity.BOTTOM;
    textView1.setLayoutParams(linearLayoutParams);
    textView1.setText("Title");
    textView1.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
    textView1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
    linearLayout.addView(textView1);


    final TextView textView2 = new TextView(mActivity);
    linearLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT);
    textView2.setLayoutParams(linearLayoutParams);
    textView2.setText("Subtitle");
    textView2.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
    textView2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
    linearLayout.addView(textView2);

    frameLayout.addView(linearLayout);


    collapsingToolbar.addView(frameLayout);
    final float SCALE_MIN=0.4f;
    AppBarLayout appBarLayout = (AppBarLayout) mActivity.findViewById(R.id.appBarLayout);
    appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int offSet) {
            float collapsedRatio = (float) offSet / appBarLayout.getTotalScrollRange();
            linearLayout.setScaleX(1 + (collapsedRatio * SCALE_MIN));
            linearLayout.setScaleY(1 + (collapsedRatio * SCALE_MIN));
            FrameLayout.LayoutParams frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
            frameLayoutParams.gravity = Gravity.BOTTOM;
            frameLayoutParams.setMargins(Math.round(dpToPixels(48) * (1+collapsedRatio)), 0, 0, Math.round(dpToPixels(15) * collapsedRatio));
            linearLayout.setLayoutParams(frameLayoutParams);
            // You can also setTransitionY/X, setAlpha, setColor etc.
        }
    });

/////

float lastCollapsedRatio = -2;

////

private int dpToPixels(int padding_in_dp){
    final float scale = getResources().getDisplayMetrics().density;
    int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
    return padding_in_px;
}
2
luca992