Skip to content Skip to sidebar Skip to footer

Coordinatorlayout Ignores Margins For Views With Anchor

Given I'm using a layout like this: Copy

Solution 2:

Try putting it in a linear layout that have padding:

<LinearLayoutwidth=".."height=".."paddingBottom="20dp"app:layout_anchor="@id/appbar"app:layout_anchorGravity="bottom|center_horizontal"><android.support.design.widget.FloatingActionButtonandroid:layout_width="70dp"android:layout_height="70dp"app:fabSize="normal" /></LinearLayout>

Solution 3:

As there might be bugs in the design-support-lib concerning the CoordinatorLayout & margins, I wrote a FrameLayout that implements/copies the same "Behavior" like the FAB and allows to set a padding to simulate the effect:

Be sure to put it in the android.support.design.widget package as it needs to access some package-scoped classes.

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.widget.FrameLayout;

import com.company.android.R;

import java.util.List;

@CoordinatorLayout.DefaultBehavior(FrameLayoutWithBehavior.Behavior.class)
publicclassFrameLayoutWithBehaviorextendsFrameLayout {
    publicFrameLayoutWithBehavior(final Context context) {
        super(context);
    }

    publicFrameLayoutWithBehavior(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    publicFrameLayoutWithBehavior(final Context context, final AttributeSet attrs, finalint defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)publicFrameLayoutWithBehavior(final Context context, final AttributeSet attrs, finalint defStyleAttr, finalint defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    publicstaticclassBehaviorextendsandroid.support.design.widget.CoordinatorLayout.Behavior<FrameLayoutWithBehavior> {
        privatestaticfinalboolean SNACKBAR_BEHAVIOR_ENABLED;
        private Rect mTmpRect;
        privateboolean mIsAnimatingOut;
        privatefloat mTranslationY;

        publicBehavior() {
        }

        @OverridepublicbooleanlayoutDependsOn(CoordinatorLayout parent, FrameLayoutWithBehavior child, View dependency) {
            return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
        }

        @OverridepublicbooleanonDependentViewChanged(CoordinatorLayout parent, FrameLayoutWithBehavior child, View dependency) {
            if (dependency instanceof Snackbar.SnackbarLayout) {
                this.updateFabTranslationForSnackbar(parent, child, dependency);
            } elseif (dependency instanceof AppBarLayout) {
                AppBarLayoutappBarLayout= (AppBarLayout) dependency;
                if (this.mTmpRect == null) {
                    this.mTmpRect = newRect();
                }

                Rectrect=this.mTmpRect;
                ViewGroupUtils.getDescendantRect(parent, dependency, rect);
                if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
                    if (!this.mIsAnimatingOut && child.getVisibility() == VISIBLE) {
                        this.animateOut(child);
                    }
                } elseif (child.getVisibility() != VISIBLE) {
                    this.animateIn(child);
                }
            }

            returnfalse;
        }

        privatevoidupdateFabTranslationForSnackbar(CoordinatorLayout parent, FrameLayoutWithBehavior fab, View snackbar) {
            floattranslationY=this.getFabTranslationYForSnackbar(parent, fab);
            if (translationY != this.mTranslationY) {
                ViewCompat.animate(fab)
                          .cancel();
                if (Math.abs(translationY - this.mTranslationY) == (float) snackbar.getHeight()) {
                    ViewCompat.animate(fab)
                              .translationY(translationY)
                              .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
                              .setListener((ViewPropertyAnimatorListener) null);
                } else {
                    ViewCompat.setTranslationY(fab, translationY);
                }

                this.mTranslationY = translationY;
            }

        }

        privatefloatgetFabTranslationYForSnackbar(CoordinatorLayout parent, FrameLayoutWithBehavior fab) {
            floatminOffset=0.0F;
            Listdependencies= parent.getDependencies(fab);
            inti=0;

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

            return minOffset;
        }

        privatevoidanimateIn(FrameLayoutWithBehavior button) {
            button.setVisibility(View.VISIBLE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                ViewCompat.animate(button)
                          .scaleX(1.0F)
                          .scaleY(1.0F)
                          .alpha(1.0F)
                          .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
                          .withLayer()
                          .setListener((ViewPropertyAnimatorListener) null)
                          .start();
            } else {
                Animationanim= android.view.animation.AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_in);
                anim.setDuration(200L);
                anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
                button.startAnimation(anim);
            }

        }

        privatevoidanimateOut(final FrameLayoutWithBehavior button) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                ViewCompat.animate(button)
                          .scaleX(0.0F)
                          .scaleY(0.0F)
                          .alpha(0.0F)
                          .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
                          .withLayer()
                          .setListener(newViewPropertyAnimatorListener() {
                              publicvoidonAnimationStart(View view) {
                                  Behavior.this.mIsAnimatingOut = true;
                              }

                              publicvoidonAnimationCancel(View view) {
                                  Behavior.this.mIsAnimatingOut = false;
                              }

                              publicvoidonAnimationEnd(View view) {
                                  Behavior.this.mIsAnimatingOut = false;
                                  view.setVisibility(View.GONE);
                              }
                          })
                          .start();
            } else {
                Animationanim= android.view.animation.AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_out);
                anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
                anim.setDuration(200L);
                anim.setAnimationListener(newAnimationUtils.AnimationListenerAdapter() {
                    publicvoidonAnimationStart(Animation animation) {
                        Behavior.this.mIsAnimatingOut = true;
                    }

                    publicvoidonAnimationEnd(Animation animation) {
                        Behavior.this.mIsAnimatingOut = false;
                        button.setVisibility(View.GONE);
                    }
                });
                button.startAnimation(anim);
            }

        }

        static {
            SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
        }
    }
}

Solution 4:

Easy workaround is to anchor a random layout to where FAB was anchored, give it specific margin, and then anchor FAB to random layout, like this

<LinearLayout
 android:orientation="horizontal"
 android:id="@+id/fab_layout"
 android:layout_width="5dp"
 android:layout_height="5dp"
 android:layout_marginRight="80dp"
 android:layout_marginEnd="80dp"
 app:layout_anchor="@id/collapsing_toolbar"
 app:layout_anchorGravity="bottom|end"/>

<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_map"
    app:layout_anchor="@id/fab_layout"
    app:elevation="6dp"
    app:pressedTranslationZ="12dp"
 />

Solution 5:

To anchor the FloatingActionButton below the AppBar like this: Fab as anchor to the AppBar

Extend the FloatingActionButton and override offsetTopAndBottom:

publicclassOffsetFloatingActionButtonextendsFloatingActionButton
{
    publicOffsetFloatingActionButton(Context context)
    {
        this(context, null);
    }

    publicOffsetFloatingActionButton(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

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

    @OverrideprotectedvoidonLayout(boolean changed, int left, int top, int right, int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);
        ViewCompat.offsetTopAndBottom(this, 0);
    }

    @OverridepublicvoidoffsetTopAndBottom(int offset)
    {
        super.offsetTopAndBottom((int) (offset + (getHeight() * 0.5f)));
    }
}

Post a Comment for "Coordinatorlayout Ignores Margins For Views With Anchor"