web-dev-qa-db-fra.com

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

Contexte

J'essaie d'ajouter la même fonctionnalité que celle montrée sur de nombreuses applications, où la zone supérieure de l'écran se rétrécit et se développe en fonction du contenu défilé.

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

Le problème

La chose est, peu importe la quantité de contenu dans NestedScrollView, cela me permet de faire défiler bien en dessous de la dernière vue du contenu, juste pour me permettre de voir l'état final de la barre d'action, ayant la taille minimale de lui-même.

En bref, voici ce que je vois en faisant défiler vers le bas (contenu modifié de l'exemple CheeseSquare):

enter image description here

alors que c'est ce que j'aimerais avoir en faisant défiler vers le bas (extrait de l'application contacts):

enter image description here

J'essaie également de corriger un bogue sur ThreePhasesBottomSheet échantillon que le défilement dans le contenu de la feuille inférieure est possible même lorsqu'il est en coup d'œil. Pour reproduire, commencez à faire défiler horizontalement (ce qui ne fait rien, car il n'y a rien à faire défiler de cette façon) puis verticalement, ce qui déclencherait en quelque sorte le défilement du contenu de la feuille inférieure.

Par conséquent, je dois y désactiver le défilement dans la méthode "transformView ()", dans le cas où "traduction

Voici comment cela fonctionne en utilisant une utilisation normale:

enter image description here

Et voici 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 les drapeaux " layout_scrollFlags ", pour changer la hauteur en wrap_content et pour supprimer le clipToPadding et les attributs fitSystemWindows.

Voici l'exemple de fichier XML, que j'ai modifié pour n'inclure qu'un seul 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 aussi essayé le code suivant:

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

mais cela permettait toujours le défilement du NestedScrollView lui-même dans l'exemple CheeseSquare , et permettait également de lancer le ( ThreePhasesBottomSheet échantillon.

Questions

  1. Que puis-je faire pour arrêter le défilement lorsqu'il n'y a plus de contenu à afficher en bas?

  2. De plus, que peut-on faire pour désactiver le défilement de NestedScrollView à tout moment (pour l'exemple ThreePhasesBottomSheet )? Quelque chose comme "setEnableScrolling (...)"?

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

C'est probablement une chose très simple à changer, mais je ne sais pas quoi ...

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

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

EDIT: pour # 2, j'ai trouvé une solution de contournement dans le fichier BottomSheetLayout.Java, pour désactiver tout ce qui est lié à la variable "sheetViewOwnsTouch", comme si elle était toujours définie sur "false". Cela permettra de voler des événements tactiles sur la feuille inférieure. Cependant, ce n'est qu'une solution de contournement, et uniquement pour ce cas. Cela provoque également certains événements tactiles qui auraient dû être gérés par d'autres vues. Je souhaite toujours savoir comment bloquer le défilement par programme, et aussi dans l'autre cas de suffisamment d'espace pour afficher le contenu.

63
android developer

Que puis-je faire pour arrêter le défilement lorsqu'il n'y a pas plus de contenu à afficher en bas?

Tout d'abord, comme je l'ai commenté ci-dessous, le défilement que vous avez dit dans votre question n'est pas du NestedScrollView. Il appartient au CollapsingToolbarLayout. L'événement de défilement de NestedScrollView ne se produit que lorsque CollapsingToolbarLayout est complètement réduit, et bien sûr il arrêtera de défiler lorsqu'il n'y aura plus de contenu à l'intérieur (en bas atteint). Pour le CollapsingToolbarLayout, il se réduira à la disposition_hauteur de sa barre d'outils (comme dans le fichier xml, vous trouverez "?attr/actionBarSize"). L'image suivante montrera que, faites attention au rectangle rouge qui est la barre d'outils (j'ai défini son arrière-plan)

BNK's image

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

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

<?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 l'échantillon Cheesesquare , j'ai personnalisé ce projet et téléchargé sur My GitHub . Je suis d'accord qu'il a encore quelques problèmes, cependant, au moins cela peut être une solution pour votre 1er problème.

S'il vous plaît, jetez un oeil. J'espère que ça aide!

12
BNK

Pour désactiver le défilement, définissez simplement NestedScrollView et sa hauteur enfant LinearLayout sur 'wrap_content'.

Cela ne fonctionnera pas complètement comme vous le souhaitez, mais au moins il ne pourra pas défiler, si le contenu tient complètement à l'écran.


En parlant de votre exemple d'application Contacts, il semble qu'il n'utilise pas CoordinatorLayout et d'autres éléments qui l'accompagnent.

Ce comportement peut être fait de cette manière:

<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 allez déplacer l'image sur défilement:

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 cela d'un de mes projets et l'ai édité pour que je puisse rater quelque chose.

0
geNia