web-dev-qa-db-fra.com

Comment désactiver le défilement de AppBarLayout dans CoordinatorLayout?

J'ai MapFragment avec effet de parallaxe à l'intérieur de AppBarLayout:

 enter image description here

Je souhaite désactiver le défilement sur AppBarLayout, car il n'est pas possible de se déplacer sur la carte, car les événements tactiles sur la carte sont toujours traités comme des événements de défilement. Je voudrais gérer la réduction de AppBarLayout en faisant défiler uniquement RecyclerView, qui se trouve en bas de l'écran.

C'est mon xml:

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

<Android.support.design.widget.AppBarLayout
    Android:id="@+id/appbar"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    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="wrap_content"
        Android:fitsSystemWindows="true"
        app:contentScrim="@color/white"
        app:expandedTitleMarginEnd="64dp"
        app:expandedTitleMarginStart="48dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
        app:titleEnabled="false">

        <FrameLayout
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            app:layout_collapseMode="parallax"
            Android:fitsSystemWindows="true">

            <fragment
                Android:id="@+id/map"
                Android:name="com.androidmapsextensions.SupportMapFragment"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent" />
        </FrameLayout>

        <Android.support.v7.widget.Toolbar
            Android:id="@+id/toolbar"
            Android:layout_width="match_parent"
            Android:layout_height="73dp"
            app:contentInsetLeft="0dp"
            app:contentInsetStart="0dp"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

            <include
                Android:id="@+id/search_bar"
                layout="@layout/layout_searchbar" />
        </Android.support.v7.widget.Toolbar>

        <View
            Android:id="@+id/toolbar_shadow"
            Android:layout_width="match_parent"
            Android:layout_height="3dp"
            Android:layout_below="@id/search_bar"
            Android:layout_gravity="bottom"
            Android:background="@drawable/toolbar_dropshadow"
            Android:visibility="gone" />
    </Android.support.design.widget.CollapsingToolbarLayout>
</Android.support.design.widget.AppBarLayout>


<RecyclerView
    Android:id="@+id/farm_list"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="@Android:color/transparent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

Merci pour votre réponse.

18
janox1x2x3

Je ne suis pas sûr de l'avoir, mais je pense que vous cherchez un DragCallback.

L’interface DragCallback permet de choisir si la vue de défilement parentale doit être contrôlée par des défilements sur la AppBarLayout.

Vous pouvez en définir un en appelant:

CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
    @Override
    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
        return false;
    }
});

En retournant toujours false, votre vue de défilement ne sera plus contrôlée par ABL.

Note: avant d'appeler ceci, vous devriez vérifier que ViewCompat.isLaidOut(appBarLayout), sinon params.getBehavior() retournera null.

46
natario

Problème

  1. AppBarLayout défile même si le contenu du défilement convient à l'écran.
  2. C'est parce que par défaut, nous pouvons faire glisser AppBarLayout en touchant et en faisant glisser AppBarLayout.

Solution

  1. Nous allons désactiver le comportement "Dragging" pour AppBarLayout.

    // Disable "Drag" for AppBarLayout (i.e. User can't scroll appBarLayout by directly touching appBarLayout - User can only scroll appBarLayout by only using scrollContent)
    if (appBarLayout.getLayoutParams() != null) {
        CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
        AppBarLayout.Behavior appBarLayoutBehaviour = new AppBarLayout.Behavior();
        appBarLayoutBehaviour.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
            @Override
            public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                return false;
            }
        });
        layoutParams.setBehavior(appBarLayoutBehaviour);
    }
    

Référence

  1. Ceci est juste une extension de la réponse acceptée de "natario" ci-dessus.

  2. https://developer.Android.com/reference/Android/support/design/widget/AppBarLayout.Behavior.DragCallback.html

25
Vasanth

Vous pouvez accomplir cela en définissant un app:layout_behavior personnalisé en xml. Avec cette approche, vous n'avez pas à vous soucier d'obtenir une référence à LayoutParams et d'effectuer des contrôles nuls. 

  <Android.support.design.widget.AppBarLayout
      Android:id="@+id/app_bar_layout"
      Android:layout_width="match_parent"
      Android:layout_height="wrap_content"
      app:layout_behavior="com.yourcompany.FixedAppBarLayoutBehavior"
      >

Créez ensuite une classe personnalisée qui s'étend de AppBarLayout.Behavior.

public class FixedAppBarLayoutBehavior extends AppBarLayout.Behavior {

  public FixedAppBarLayoutBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);

    setDragCallback(new DragCallback() {
      @Override public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
        return false;
      }
    });
  }
}

Mise à jour avec la version Kotlin:

class FixedAppBarLayoutBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.Behavior(context, attrs) {
  init {
    setDragCallback(object : DragCallback() {
      override fun canDrag(appBarLayout: AppBarLayout): Boolean = false
    })
  }
}
12
Victor Rendina

Donc, après deux heures d’essais, j’ai trouvé une solution assez simple. J'avais juste besoin d'étendre la variable CoordinatorLayout et de remplacer la méthode OnInterceptTouchEvent pour que la classe ressemble à ceci: 

public class NonTouchableCoordinatorLayout extends CoordinatorLayout {
public NonTouchableCoordinatorLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return false;
}

}

5
janox1x2x3

vous pouvez utiliser la NestedScrollView.setNestedScrollingEnabled(false) pour désactiver l'événement Scroll suivant de AppBarLayout

0
JinJieGoo