7

La mia barra delle applicazioni nasconde una delle mie viste quando raggiunge la fine dello scorrimento, ma voglio che la vista bloccata rimanga sopra l'AppBar anche quando raggiunge la fine del suo scorrimento.AppBar nasconde la vista durante lo scorrimento finché non è compresso

Ecco ciò che la mia vista appare come prima di iniziare lo scorrimento:

e questo è quello che sembra quando è completamente fatto scorrere:

Si può vedere che l'immagine circolare sulla in basso a sinistra dell'AppBar è ora nascosto sotto la barra.

Qui è il codice XML del mio frammento:

<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="150dp" 
     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="@color/translucent" 
      app:expandedTitleMarginEnd="64dp" 
      app:expandedTitleMarginStart="48dp" 
      app:layout_scrollFlags="scroll|exitUntilCollapsed"> 

      <ImageView 
       android:id="@+id/backdrop" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" 
       android:background="@color/dark_gray" 
       android:fitsSystemWindows="true" 
       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.support.v4.widget.NestedScrollView> 


    <de.hdodenhof.circleimageview.CircleImageView 
     android:id="@+id/profile_image" 
     android:layout_width="80dp" 
     android:layout_height="80dp" 
     android:layout_margin="16dp" 
     android:fitsSystemWindows="true" 
     android:src="@drawable/default_profile" 
     app:border_color="@android:color/white" 
     app:border_width="2dp" 
     app:layout_anchor="@id/appbar" 
     app:layout_anchorGravity="bottom|left|end" /> 

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

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

Come posso risolvere questo problema in modo che l'imageview circolare in basso a sinistra del AppBar rimane al di sopra anche quando raggiunge la fine del suo scorrimento?

+0

Non è stato possibile ricreare il problema. – tachyonflux

+0

Non riesco a capire la tua domanda molto bene. – SilentKnight

+0

Mi dispiace per quello. Fondamentalmente, il CircularImageView in basso a sinistra dell'AppBar (il cerchio nero con un bordo bianco) si trova in cima all'AppBar mentre l'utente sta scorrendo. Come puoi vedere, l'AppBar inizia con un'altezza di 150 dp e quindi si riduce in altezza mentre l'utente sta scorrendo. Proprio quando l'AppBar raggiunge la sua altezza minima, CircularImageView si sposta dietro all'AppBar. Come faccio a fare in modo che CircularImageView non si sposta dietro l'AppBar anche quando l'AppBar è all'altezza minima. Posso solo riprodurre questo problema in Android L. Non si verifica in KitKat. –

risposta

3

Mi trovavo di fronte allo stesso problema di oggi e potrei sistemarlo subito.

Quello che ho dovuto fare è stato creare una visualizzazione personalizzata come questo:

package com.github.rodrigohenriques.samples.customview; 

import android.animation.Animator; 
import android.animation.AnimatorListenerAdapter; 
import android.annotation.TargetApi; 
import android.content.Context; 
import android.graphics.Matrix; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.os.Build; 
import android.support.design.widget.AppBarLayout; 
import android.support.design.widget.CoordinatorLayout; 
import android.support.design.widget.Snackbar; 
import android.support.v4.view.ViewCompat; 
import android.support.v4.view.ViewPropertyAnimatorListener; 
import android.support.v4.view.animation.FastOutSlowInInterpolator; 
import android.util.AttributeSet; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.ViewParent; 
import android.widget.ImageView; 

import java.util.List; 

@CoordinatorLayout.DefaultBehavior(CoordinatedImageView.Behavior.class) 
public class CoordinatedImageView extends ImageView { 

    private boolean mIsHiding; 

    public CoordinatedImageView(Context context) { 
     super(context); 
    } 

    public CoordinatedImageView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public CoordinatedImageView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
    } 

    @TargetApi(Build.VERSION_CODES.LOLLIPOP) 
    public CoordinatedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 
    } 

    public void hide() { 
     if(!this.mIsHiding && this.getVisibility() == VISIBLE) { 
      if(ViewCompat.isLaidOut(this) && !this.isInEditMode()) { 
       this.animate().scaleX(0.0F).scaleY(0.0F).alpha(0.0F).setDuration(200L).setInterpolator(new FastOutSlowInInterpolator()).setListener(new AnimatorListenerAdapter() { 
        public void onAnimationStart(Animator animation) { 
         CoordinatedImageView.this.mIsHiding = true; 
         CoordinatedImageView.this.setVisibility(VISIBLE); 
        } 

        public void onAnimationCancel(Animator animation) { 
         CoordinatedImageView.this.mIsHiding = false; 
        } 

        public void onAnimationEnd(Animator animation) { 
         CoordinatedImageView.this.mIsHiding = false; 
         CoordinatedImageView.this.setVisibility(GONE); 
        } 
       }); 
      } else { 
       this.setVisibility(GONE); 
      } 
     } 
    } 

    public void show() { 
     if(this.getVisibility() != VISIBLE) { 
      if(ViewCompat.isLaidOut(this) && !this.isInEditMode()) { 
       this.setAlpha(0.0F); 
       this.setScaleY(0.0F); 
       this.setScaleX(0.0F); 
       this.animate().scaleX(1.0F).scaleY(1.0F).alpha(1.0F).setDuration(200L).setInterpolator(new FastOutSlowInInterpolator()).setListener(new AnimatorListenerAdapter() { 
        public void onAnimationStart(Animator animation) { 
         CoordinatedImageView.this.setVisibility(VISIBLE); 
        } 
       }); 
      } else { 
       this.setVisibility(VISIBLE); 
       this.setAlpha(1.0F); 
       this.setScaleY(1.0F); 
       this.setScaleX(1.0F); 
      } 
     } 
    } 

    public static class Behavior extends android.support.design.widget.CoordinatorLayout.Behavior<CoordinatedImageView> { 
     private static final boolean SNACKBAR_BEHAVIOR_ENABLED; 
     private Rect mTmpRect; 

     public Behavior() { 
     } 

     public boolean layoutDependsOn(CoordinatorLayout parent, CoordinatedImageView child, View dependency) { 
      return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout; 
     } 

     public boolean onDependentViewChanged(CoordinatorLayout parent, CoordinatedImageView child, View dependency) { 
      if(dependency instanceof Snackbar.SnackbarLayout) { 
       this.updateFabTranslationForSnackbar(parent, child, dependency); 
      } else if(dependency instanceof AppBarLayout) { 
       this.updateFabVisibility(parent, (AppBarLayout)dependency, child); 
      } 

      return false; 
     } 

     public void onDependentViewRemoved(CoordinatorLayout parent, CoordinatedImageView child, View dependency) { 
      if(dependency instanceof Snackbar.SnackbarLayout && ViewCompat.getTranslationY(child) != 0.0F) { 
       ViewCompat.animate(child).translationY(0.0F).scaleX(1.0F).scaleY(1.0F).alpha(1.0F).setInterpolator(new FastOutSlowInInterpolator()).setListener((ViewPropertyAnimatorListener)null); 
      } 

     } 

     private boolean updateFabVisibility(CoordinatorLayout parent, AppBarLayout appBarLayout, CoordinatedImageView child) { 
      CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)child.getLayoutParams(); 
      if(lp.getAnchorId() != appBarLayout.getId()) { 
       return false; 
      } else { 
       if(this.mTmpRect == null) { 
        this.mTmpRect = new Rect(); 
       } 

       Rect rect = this.mTmpRect; 
       ViewGroupUtils.getDescendantRect(parent, appBarLayout, rect); 
       if(rect.bottom <= getMinimumHeightForVisibleOverlappingContent(appBarLayout)) { 
        child.hide(); 
       } else { 
        child.show(); 
       } 

       return true; 
      } 
     } 

     private int getMinimumHeightForVisibleOverlappingContent(AppBarLayout appBarLayout) { 
      int minHeight = ViewCompat.getMinimumHeight(appBarLayout); 
      if(minHeight != 0) { 
       return minHeight * 2; 
      } else { 
       int childCount = appBarLayout.getChildCount(); 
       return childCount >= 1?ViewCompat.getMinimumHeight(appBarLayout.getChildAt(childCount - 1)) * 2 :0; 
      } 
     } 

     private void updateFabTranslationForSnackbar(CoordinatorLayout parent, CoordinatedImageView imageView, View snackbar) { 
      if(imageView.getVisibility() == 0) { 
       float translationY = this.getFabTranslationYForSnackbar(parent, imageView); 
       ViewCompat.setTranslationY(imageView, translationY); 
      } 
     } 

     private float getFabTranslationYForSnackbar(CoordinatorLayout parent, CoordinatedImageView imageView) { 
      float minOffset = 0.0F; 
      List dependencies = parent.getDependencies(imageView); 
      int i = 0; 

      for(int z = dependencies.size(); i < z; ++i) { 
       View view = (View)dependencies.get(i); 
       if(view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(imageView, view)) { 
        minOffset = Math.min(minOffset, ViewCompat.getTranslationY(view) - (float)view.getHeight()); 
       } 
      } 

      return minOffset; 
     } 

     public boolean onLayoutChild(CoordinatorLayout parent, CoordinatedImageView child, int layoutDirection) { 
      List dependencies = parent.getDependencies(child); 
      int i = 0; 

      for(int count = dependencies.size(); i < count; ++i) { 
       View dependency = (View)dependencies.get(i); 
       if(dependency instanceof AppBarLayout && this.updateFabVisibility(parent, (AppBarLayout)dependency, child)) { 
        break; 
       } 
      } 

      parent.onLayoutChild(child, layoutDirection); 
      this.offsetIfNeeded(parent, child); 
      return true; 
     } 

     private void offsetIfNeeded(CoordinatorLayout parent, CoordinatedImageView imageView) { 
      Rect padding = new Rect(imageView.getPaddingLeft(), imageView.getPaddingTop(), imageView.getPaddingRight(), imageView.getPaddingBottom()); 
      if(padding.centerX() > 0 && padding.centerY() > 0) { 
       CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)imageView.getLayoutParams(); 
       int offsetTB = 0; 
       int offsetLR = 0; 
       if(imageView.getRight() >= parent.getWidth() - lp.rightMargin) { 
        offsetLR = padding.right; 
       } else if(imageView.getLeft() <= lp.leftMargin) { 
        offsetLR = -padding.left; 
       } 

       if(imageView.getBottom() >= parent.getBottom() - lp.bottomMargin) { 
        offsetTB = padding.bottom; 
       } else if(imageView.getTop() <= lp.topMargin) { 
        offsetTB = -padding.top; 
       } 

       imageView.offsetTopAndBottom(offsetTB); 
       imageView.offsetLeftAndRight(offsetLR); 
      } 

     } 

     static { 
      SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11; 
     } 
    } 

    private static class ViewGroupUtils { 
     private static final ViewGroupUtils.ViewGroupUtilsImpl IMPL; 

     ViewGroupUtils() { 
     } 

     static void offsetDescendantRect(ViewGroup parent, View descendant, Rect rect) { 
      IMPL.offsetDescendantRect(parent, descendant, rect); 
     } 

     static void getDescendantRect(ViewGroup parent, View descendant, Rect out) { 
      out.set(0, 0, descendant.getWidth(), descendant.getHeight()); 
      offsetDescendantRect(parent, descendant, out); 
     } 

     static { 
      int version = Build.VERSION.SDK_INT; 
      if(version >= 11) { 
       IMPL = new ViewGroupUtils.ViewGroupUtilsImplHoneycomb(); 
      } else { 
       IMPL = new ViewGroupUtils.ViewGroupUtilsImplBase(); 
      } 

     } 

     private static class ViewGroupUtilsImplHoneycomb implements ViewGroupUtils.ViewGroupUtilsImpl { 
      private ViewGroupUtilsImplHoneycomb() { 
      } 

      public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) { 
       ViewGroupUtilsHoneycomb.offsetDescendantRect(parent, child, rect); 
      } 
     } 

     private static class ViewGroupUtilsImplBase implements ViewGroupUtils.ViewGroupUtilsImpl { 
      private ViewGroupUtilsImplBase() { 
      } 

      public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) { 
       parent.offsetDescendantRectToMyCoords(child, rect); 
      } 
     } 

     private interface ViewGroupUtilsImpl { 
      void offsetDescendantRect(ViewGroup var1, View var2, Rect var3); 
     } 
    } 

    private static class ViewGroupUtilsHoneycomb { 
     private static final ThreadLocal<Matrix> sMatrix = new ThreadLocal(); 
     private static final ThreadLocal<RectF> sRectF = new ThreadLocal(); 
     private static final Matrix IDENTITY = new Matrix(); 

     ViewGroupUtilsHoneycomb() { 
     } 

     public static void offsetDescendantRect(ViewGroup group, View child, Rect rect) { 
      Matrix m = (Matrix)sMatrix.get(); 
      if(m == null) { 
       m = new Matrix(); 
       sMatrix.set(m); 
      } else { 
       m.set(IDENTITY); 
      } 

      offsetDescendantMatrix(group, child, m); 
      RectF rectF = (RectF)sRectF.get(); 
      if(rectF == null) { 
       rectF = new RectF(); 
      } 

      rectF.set(rect); 
      m.mapRect(rectF); 
      rect.set((int)(rectF.left + 0.5F), (int)(rectF.top + 0.5F), (int)(rectF.right + 0.5F), (int)(rectF.bottom + 0.5F)); 
     } 

     static void offsetDescendantMatrix(ViewParent target, View view, Matrix m) { 
      ViewParent parent = view.getParent(); 
      if(parent instanceof View && parent != target) { 
       View vp = (View)parent; 
       offsetDescendantMatrix(target, vp, m); 
       m.preTranslate((float)(-vp.getScrollX()), (float)(-vp.getScrollY())); 
      } 

      m.preTranslate((float)view.getLeft(), (float)view.getTop()); 
      if(!view.getMatrix().isIdentity()) { 
       m.preConcat(view.getMatrix()); 
      } 

     } 
    } 
} 

e quindi utilizzare questa visualizzazione personalizzata in mio layout:

<?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" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fitsSystemWindows="true" 
    tools:context=".ScrollingActivity"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/app_bar" 
     android:layout_width="match_parent" 
     android:layout_height="@dimen/app_bar_height" 
     android:fitsSystemWindows="true" 
     android:theme="@style/AppTheme.AppBarOverlay"> 

     <android.support.design.widget.CollapsingToolbarLayout 
      android:id="@+id/toolbar_layout" 
      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:scaleType="centerCrop" 
       android:fitsSystemWindows="true" 
       android:src="@drawable/image" 
       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/AppTheme.PopupOverlay" /> 

     </android.support.design.widget.CollapsingToolbarLayout> 
    </android.support.design.widget.AppBarLayout> 

    <include layout="@layout/content_scrolling" /> 

    <android.support.design.widget.FloatingActionButton 
     android:id="@+id/fab" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_margin="@dimen/fab_margin" 
     android:src="@android:drawable/ic_dialog_email" 
     app:layout_anchor="@id/app_bar" 
     app:layout_anchorGravity="bottom|end" /> 

    <com.github.rodrigohenriques.samples.customview.CoordinatedImageView 
     android:id="@+id/logo" 
     android:layout_width="72dp" 
     android:layout_height="72dp" 
     android:scaleType="centerCrop" 
     android:src="@drawable/image" 
     android:layout_margin="@dimen/fab_margin" 
     app:layout_anchor="@id/app_bar" 
     app:layout_anchorGravity="bottom|start" /> 

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

Ho anche creato un gist: https://gist.github.com/rodrigohenriques/123f2c6a40b95e00e145

Buona fortuna a te amico.

Spero che sia d'aiuto.

1

anche io ho sofferto di questo problema. Dopo molte riflessioni sono riuscito a sopravvivere da quella situazione.

In realtà l'appbar sta già avendo l'elevazione, ecco perché fa in modo che tutte le viste si inseriscano da sé.

Quindi è sufficiente dare app:elevation="0dp" al layout dell'appbar. Dà a tutti gli altri punti di vista la libertà di rimanere su se stessa.

Problemi correlati