7

Meine AppBar verbirgt eine meiner Ansichten direkt, wenn sie das Ende des Scrollen erreicht, aber ich möchte, dass die fixierte Ansicht über der AppBar bleibt, auch wenn sie das Ende des Scrollen erreicht. HierAppBar blendet Ansicht beim Scrollen bis zum Einklappen

ist, was meiner Meinung nach aussieht, bevor ich beginne Scrollen:

Und das ist, wie es aussieht, wenn es vollständig gescrollt wird:

Sie können sehen, dass das Kreisbild auf der Unten links der AppBar ist jetzt unter der Leiste versteckt.

Hier wird XML-Code meines Fragment:

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

Wie behebe ich das so, dass die kreisförmige Bildansicht auf dem Boden des AppBar links sogar darüber bleibt, wenn es das Ende seiner Scrollen erreicht?

+0

Ich konnte Ihr Problem nicht neu erstellen. – tachyonflux

+0

Ich kann Ihre Frage nicht gut verstehen. – SilentKnight

+0

Entschuldigung. Grundsätzlich befindet sich die CircularImageView unten links in der AppBar (der schwarze Kreis mit einem weißen Rand) über der AppBar, während der Benutzer scrollt. Wie Sie sehen können, beginnt die AppBar mit einer Höhe von 150 dpi und verringert sich dann in der Höhe, während der Benutzer scrollt. Wenn die AppBar ihre minimale Höhe erreicht, bewegt sich das CircularImageView hinter der AppBar. Wie mache ich es so, dass die CircularImageView nicht hinter der AppBar bewegt, auch wenn die AppBar auf der minimalen Höhe ist. Ich kann dieses Problem nur in Android L reproduzieren. Es tritt nicht in KitKat auf. –

Antwort

3

Ich hatte das gleiche Problem wie Sie heute und ich konnte es jetzt beheben.

Was ich tun musste, war eine benutzerdefinierte Ansicht wie folgt zu erstellen:

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()); 
      } 

     } 
    } 
} 

Und dann diese benutzerdefinierte Ansicht in meinem Layout verwenden:

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

ich auch einen Kern erstellt: https://gist.github.com/rodrigohenriques/123f2c6a40b95e00e145

Viel Glück für Sie Kumpel.

Hoffe, dass es hilft.

1

Ich war auch von diesem Problem betroffen. Nach vielem Nachdenken konnte ich von dieser Situation überleben.

Eigentlich hat die Appbar bereits die Elevation, deshalb macht sie alle Ansichten in sich hinein.

Also müssen Sie nur app:elevation="0dp" auf die Appbar-Layout geben. Es gibt allen anderen Ansichten die Freiheit, über sich selbst zu bleiben.

Verwandte Themen