64 votes

Comment désactiver le défilement de NestedScrollView & CollapsingToolbarLayout, par exemple lorsqu'il n'y a plus de contenu ci-dessous?

Arrière-plan

J'essaie d'ajouter la même fonctionnalité comme illustré sur de nombreuses applications, où la partie supérieure de l'écran se rétrécit&se dilate en fonction de la défilé de contenu.

Pour cela, j'utilise Google bibliothèque de conception, comme illustré sur la CheeseSquare de l'échantillon.

Le problème

C'est que, n'importe comment beaucoup de contenu, il est dans le NestedScrollView , ça me permet de faire défiler au-dessous de la dernière vue du contenu, juste de me laisser voir l'état final de l'actionbar, ayant la taille minimale de lui-même.

En bref, c'est ce que je vois lorsque le défilement vers le bas (modifié le contenu de CheeseSquare de l'échantillon):

enter image description here

alors que c'est ce que j'aimerais avoir en cas de défilement vers le bas (prises à partir de l'application de contacts) :

enter image description here

Je suis aussi en train d'essayer de corriger un bug sur ThreePhasesBottomSheet échantillon de défilement en bas de la feuille de contenu est possible, même quand il est en peek-état. De reproduire, de commencer à faire défiler horizontalement (ce qui ne veut pas faire n'importe quoi, comme il n'y a rien à faire défiler de cette façon) et puis à la verticale, ce qui serait en quelque sorte de déclencher le défilement du contenu de la partie inférieure de la feuille.

Donc, j'ai besoin de désactiver il y a le défilement dans "transformView()" la méthode, dans le cas que "la traduction

C'est la façon dont il fonctionne à l'aide de l'utilisation normale:

enter image description here

Et c'est comment il se comporte avec le bug de ne pas bloquer le défilement:

enter image description here

Ce que j'ai essayé

J'ai essayé de jouer avec le "layout_scrollFlags" drapeaux, pour modifier la hauteur de wrap_content, et de supprimer les clipToPadding et fitsSystemWindows attributs.

Voici l'exemple de fichier XML, que j'ai modifié pour inclure qu'une seule cardView au lieu de plusieurs:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <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:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin" />

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

        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"
        android:src="@drawable/ic_discuss"
        android:layout_margin="@dimen/fab_margin"
        android:clickable="true"/>

</android.support.design.widget.CoordinatorLayout>

J'ai essayé le code suivant aussi :

((AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams()).setScrollFlags(0);

mais il y a encore permis de défilement de la NestedScrollView lui-même dans le CheeseSquare exemple, et permet aussi la jetant dans le ThreePhasesBottomSheet de l'échantillon .

Les questions

  1. Que puis-je faire afin de rendre le défilement s'arrêter quand il n'y a pas plus de contenu à afficher au bas de l'échelle?

  2. En outre, ce qui peut être fait pour désactiver le défilement de la NestedScrollView en tout temps, je souhaite ( pour le ThreePhasesBottomSheet exemple) ? Quelque chose comme "setEnableScrolling(...)" ?

    J'ai essayé d'étendre NestedScrollView et également s'étendre à partir de ScrollingViewBehavior, mais pas réussi à trouver ce qui peut être fait pour désactiver le défilement.

C'est probablement une chose très simple à changer, mais je ne peux pas trouver ce que...

EDIT: si nécessaire, c'est ce que j'utilise actuellement pour la conception et la bibliothèque de prise en charge

compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.android.support:design:23.1.0'

EDIT: pour le #2, j'ai trouvé une solution de contournement à partir de l'intérieur de la BottomSheetLayout.java fichier, de désactiver tout ce qui est lié à la variable "sheetViewOwnsTouch", comme si c'est toujours la valeur "false". Cela permettra de voler les événements tactiles sur le bas de la feuille. Cependant, c'est juste une solution de contournement, et seulement dans ce cas. Il provoque aussi certains événements tactiles qui doit avoir été traité par d'autres points de vue. Je souhaite toujours de savoir comment faire pour bloquer le défilement de la programmation, et aussi dans les autres cas de suffisamment d'espace-pour-afficher-le contenu.

12voto

BNK Points 7177

Que puis-je faire afin de rendre le défilement s'arrêter quand il n'y a pas de plus de contenu à afficher au bas de l'échelle?

Tout d'abord, comme je l'ai expliqué ci-après, le défilement vous avez dit dans votre question n'est pas de l' NestedScrollView. Il appartient à l' CollapsingToolbarLayout. L' NestedScrollView's défiler événement ne se produit que lorsque CollapsingToolbarLayout entièrement effondré, et bien sûr, il va arrêter le défilement quand il n'y a pas plus de contenu à l'intérieur (en bas atteint). Pour l' CollapsingToolbarLayout, il va s'effondrer à sa Barre d'outils du layout_height (comme dans le fichier xml, vous trouverez "?attr/actionBarSize"). L'image suivante sera de démontrer que, prêter attention à la rouge rectangulaire qui est de la barre d'outils (j'ai mis son arrière-plan)

BNK's image

Afin d'avoir une solution pour votre #1, vous devez calculer la hauteur d' NestedScrollView, puis si elle est plus petite que la hauteur de l'écran, nous fixons la barre d'outils de la hauteur.

En bref, vous pouvez mettre à jour activity_detail.xml que:

<?xml version="1.0" encoding="utf-8"?>

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/detail_backdrop_height"
        android:fitsSystemWindows="true"
        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"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="false"
                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="wrap_content"            
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

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

        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

Et CheeseDetailActivity.java:

public class CheeseDetailActivity extends AppCompatActivity {

    public static final String EXTRA_NAME = "cheese_name";
    private final Context mContext = this;
    private int screenHeight;
    private int linearLayoutHeight;
    private int toolbarHeight_org;
    private int toolbarHeight;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        Intent intent = getIntent();
        final String cheeseName = intent.getStringExtra(EXTRA_NAME);

        screenHeight = getScreenHeight(this);

        TypedValue typedValue = new TypedValue();
        getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
        final int colorPrimary = typedValue.data;

        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar);
        final CoordinatorLayout.LayoutParams appbarLayoutParams = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();

        final ViewGroup.LayoutParams toolbarLayoutParams = toolbar.getLayoutParams();
        if (toolbarLayoutParams != null) {
            toolbarHeight_org = toolbarLayoutParams.height;
            toolbarHeight = toolbarLayoutParams.height;
        }

        final CollapsingToolbarLayout collapsingToolbar =
                (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle(cheeseName);

        collapsingToolbar.setContentScrimColor(colorPrimary);
        collapsingToolbar.setExpandedTitleTextAppearance(R.style.ExpandedTitleTextAppearance);
        //collapsingToolbar.setCollapsedTitleTextAppearance(R.style.CollapsedTitleTextAppearance);

        final LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linearLayout1);
        ViewTreeObserver observer = linearLayout.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                linearLayoutHeight = linearLayout.getHeight();
                if (linearLayoutHeight + toolbarHeight < screenHeight) {
                    if (toolbarLayoutParams != null) {
                        toolbarLayoutParams.height = screenHeight - linearLayoutHeight - 20;
                        if (toolbarLayoutParams.height < toolbarHeight_org) {
                            toolbarLayoutParams.height = toolbarHeight_org;
                        }

                        int extended_text_size = (int) getResources().getDimension(R.dimen.expanded_text_size);

                        if (appbarLayoutParams.height - toolbarLayoutParams.height <= extended_text_size) {
                            int value = appbarLayoutParams.height - toolbarLayoutParams.height;
                            if (value < 0) {
                                appbarLayoutParams.height = toolbarLayoutParams.height - value + extended_text_size * 3;
                            } else {
                                appbarLayoutParams.height = toolbarLayoutParams.height + extended_text_size * 3;
                            }
                            if (appbarLayoutParams.height >= screenHeight) {
                                appbarLayoutParams.height = screenHeight;
                            }
                        }

                        // collapsingToolbar.setContentScrimColor(getResources().getColor(android.R.color.transparent));
                        if (toolbarLayoutParams.height > toolbarHeight_org) {
                            collapsingToolbar.setContentScrimColor(ContextCompat.getColor(mContext, android.R.color.transparent));
                        }
                    }
                }
                // Removes the listener if possible
                ViewTreeObserver viewTreeObserver = linearLayout.getViewTreeObserver();
                if (viewTreeObserver.isAlive()) {
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                        linearLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    } else {
                        linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
                }
            }
        });

        loadBackdrop();
        appbar.setExpanded(true);
    }

    private int getScreenHeight(Context context) {
        int measuredHeight;
        Point size = new Point();
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            wm.getDefaultDisplay().getSize(size);
            measuredHeight = size.y;
        } else {
            Display d = wm.getDefaultDisplay();
            measuredHeight = d.getHeight();
        }

        return measuredHeight;
    }

    private void loadBackdrop() {
        final ImageView imageView = (ImageView) findViewById(R.id.backdrop);
        Glide.with(this).load(Cheeses.getRandomCheeseDrawable()).centerCrop().into(imageView);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.sample_actions, menu);
        return true;
    }
}

Voici le résultat:

BNK's screenshot

Avec Cheesesquare exemple, j'ai personnalisé ce projet et téléchargées sur Mon GitHub. Je suis d'accord qu'il y a encore quelques problèmes, mais, au moins, il peut être une solution pour votre 1ère question.

Veuillez prendre un coup d'oeil. Espérons que cela aide!

0voto

geNia Points 456

Pour désactiver le défilement, il suffit de mettre les deux NestedScrollView et c'est LinearLayout enfant hauteur de "wrap_content'.

Qui ne sera pas tout à fait comme vous le voulez, mais au moins il ne sera pas de défilement, si le contenu s'adapte à l'écran complètement.


Parler de votre application Contacts exemple, on dirait qu'elle n'est pas à l'aide de CoordinatorLayout et d'autres choses qui vont avec.

Ce comportement peut être fait de cette façon:

<ScrollView
    android:id="@+id/scroll_adinfo"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="@dimen/image_height"
            android:src="@mipmap/ic_launcher"/>

        <LinearLayout
            android:id="@+id/layout_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="@dimen/image_height">

            <!-- YOUR CONTENT HERE -->
        </LinearLayout>
    </FrameLayout>
</ScrollView>

Et dans votre code vous permettra de déplacer l'image sur le parchemin:

final ImageView image = (ImageView) findViewById(R.id.image);

((ScrollView) rootView.findViewById(R.id.scroll_adinfo)).getViewTreeObserver().addOnScrollChangedListener(
            new ViewTreeObserver.OnScrollChangedListener() {

                @Override
                public void onScrollChanged() {
                    int scrollY = ((ScrollView) rootView.findViewById(R.id.scroll_adinfo)).getScrollY();

                    image.setY(scrollY / 2);
                }
            });

J'ai extrait d'un de mes projets et édité, donc je ne peux manquer de quelque chose.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X