CoordinatorLayout 忽略带有锚点的视图的边距
CoordinatorLayout ignores margins for views with anchor
鉴于我使用的是这样的布局:
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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/flexible_space_image_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:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:statusBarScrim="@android:color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<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.v7.widget.RecyclerView
android:id="@+id/mainView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
<android.support.design.widget.FloatingActionButton
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginBottom="20dp"
app:fabSize="normal"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|center_horizontal"
/>
</android.support.design.widget.CoordinatorLayout>
这几乎是标准 Cheesesquare 示例 - 除了 FloatingActionButton,我想将其向上移动约 20dp。
但是,这是行不通的。无论我是否使用边距、填充等 - 按钮将始终在锚点的边缘居中,如下所示:
如何按预期将 FAB 向上移动 20dp?
尝试将其置于具有填充的线性布局中:
<LinearLayout
width=".."
height=".."
paddingBottom="20dp"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|center_horizontal">
<android.support.design.widget.FloatingActionButton
android:layout_width="70dp"
android:layout_height="70dp"
app:fabSize="normal" />
</LinearLayout>
由于设计支持库中可能有 bugs 关于 CoordinatorLayout
和边距,我写了一个 FrameLayout
与 implements/copies 相同 "Behavior" 喜欢 FAB 并允许设置一个 padding
来模拟效果:
一定要把它放在 android.support.design.widget
包中,因为它需要访问一些包范围的 类。
/*
* 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)
public class FrameLayoutWithBehavior extends FrameLayout {
public FrameLayoutWithBehavior(final Context context) {
super(context);
}
public FrameLayoutWithBehavior(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public FrameLayoutWithBehavior(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public FrameLayoutWithBehavior(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public static class Behavior extends android.support.design.widget.CoordinatorLayout.Behavior<FrameLayoutWithBehavior> {
private static final boolean SNACKBAR_BEHAVIOR_ENABLED;
private Rect mTmpRect;
private boolean mIsAnimatingOut;
private float mTranslationY;
public Behavior() {
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FrameLayoutWithBehavior child, View dependency) {
return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FrameLayoutWithBehavior child, View dependency) {
if (dependency instanceof Snackbar.SnackbarLayout) {
this.updateFabTranslationForSnackbar(parent, child, dependency);
} else if (dependency instanceof AppBarLayout) {
AppBarLayout appBarLayout = (AppBarLayout) dependency;
if (this.mTmpRect == null) {
this.mTmpRect = new Rect();
}
Rect rect = this.mTmpRect;
ViewGroupUtils.getDescendantRect(parent, dependency, rect);
if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
if (!this.mIsAnimatingOut && child.getVisibility() == VISIBLE) {
this.animateOut(child);
}
} else if (child.getVisibility() != VISIBLE) {
this.animateIn(child);
}
}
return false;
}
private void updateFabTranslationForSnackbar(CoordinatorLayout parent, FrameLayoutWithBehavior fab, View snackbar) {
float translationY = 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;
}
}
private float getFabTranslationYForSnackbar(CoordinatorLayout parent, FrameLayoutWithBehavior fab) {
float minOffset = 0.0F;
List dependencies = parent.getDependencies(fab);
int i = 0;
for (int z = dependencies.size(); i < z; ++i) {
View view = (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;
}
private void animateIn(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 {
Animation anim = 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);
}
}
private void animateOut(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(new ViewPropertyAnimatorListener() {
public void onAnimationStart(View view) {
Behavior.this.mIsAnimatingOut = true;
}
public void onAnimationCancel(View view) {
Behavior.this.mIsAnimatingOut = false;
}
public void onAnimationEnd(View view) {
Behavior.this.mIsAnimatingOut = false;
view.setVisibility(View.GONE);
}
})
.start();
} else {
Animation anim = android.view.animation.AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_out);
anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
anim.setDuration(200L);
anim.setAnimationListener(new AnimationUtils.AnimationListenerAdapter() {
public void onAnimationStart(Animation animation) {
Behavior.this.mIsAnimatingOut = true;
}
public void onAnimationEnd(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;
}
}
}
简单的解决方法是将随机布局锚定到 FAB 锚定的位置,为其指定特定边距,然后将 FAB 锚定到随机布局,就像这样
<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"
/>
要将 FloatingActionButton
锚定在 AppBar
下方,如下所示:
扩展 FloatingActionButton
并覆盖 offsetTopAndBottom
:
public class OffsetFloatingActionButton extends FloatingActionButton
{
public OffsetFloatingActionButton(Context context)
{
this(context, null);
}
public OffsetFloatingActionButton(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public OffsetFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
ViewCompat.offsetTopAndBottom(this, 0);
}
@Override
public void offsetTopAndBottom(int offset)
{
super.offsetTopAndBottom((int) (offset + (getHeight() * 0.5f)));
}
}
我可以通过使用 layout_anchor
layout_anchorGravity
和一些填充来解决这个问题。锚属性允许你有一个 View
相对于另一个的位置看法。但是,它的工作方式与 RelativeLayout
的工作方式并不完全相同。更多相关内容。
layout_anchor
指定您想要的 View
应该放置在哪个 View
中(即,这个 View
应该相对于由layout_anchor
属性)。然后,layout_anchorGravity
使用典型的 Gravity 值(top
、bottom
指定当前 View
将位于相对 View
的哪一侧, center_horizontal
, 等等).
单独使用这两个属性的问题是 View
的 center 与锚点将相对于另一个 View
放置.例如,如果您指定将 FloatingActionButton
锚定到 TextView
的底部,最终真正发生的是 FAB 的 center 是沿着 TextView
的底部边缘放置。
为了解决这个问题,我对 FAB 应用了一些填充,足以使 FAB 的顶部边缘接触 TextView
:
的底部边缘
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_anchor="@id/your_buttons_id_here"
android:layout_anchorGravity="bottom"
android:paddingTop=16dp" />
您可能需要增加填充才能获得所需的效果。希望对您有所帮助!
我为您推荐一个优雅的解决方案:
<android.support.design.widget.FloatingActionButton
...
android:translationY="-20dp"
...
/>
我将 app:useCompatPadding="true"
与 FAB 一起使用,一切正常。
鉴于我使用的是这样的布局:
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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/flexible_space_image_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:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:statusBarScrim="@android:color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<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.v7.widget.RecyclerView
android:id="@+id/mainView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
<android.support.design.widget.FloatingActionButton
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginBottom="20dp"
app:fabSize="normal"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|center_horizontal"
/>
</android.support.design.widget.CoordinatorLayout>
这几乎是标准 Cheesesquare 示例 - 除了 FloatingActionButton,我想将其向上移动约 20dp。
但是,这是行不通的。无论我是否使用边距、填充等 - 按钮将始终在锚点的边缘居中,如下所示:
如何按预期将 FAB 向上移动 20dp?
尝试将其置于具有填充的线性布局中:
<LinearLayout
width=".."
height=".."
paddingBottom="20dp"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|center_horizontal">
<android.support.design.widget.FloatingActionButton
android:layout_width="70dp"
android:layout_height="70dp"
app:fabSize="normal" />
</LinearLayout>
由于设计支持库中可能有 bugs 关于 CoordinatorLayout
和边距,我写了一个 FrameLayout
与 implements/copies 相同 "Behavior" 喜欢 FAB 并允许设置一个 padding
来模拟效果:
一定要把它放在 android.support.design.widget
包中,因为它需要访问一些包范围的 类。
/*
* 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)
public class FrameLayoutWithBehavior extends FrameLayout {
public FrameLayoutWithBehavior(final Context context) {
super(context);
}
public FrameLayoutWithBehavior(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public FrameLayoutWithBehavior(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public FrameLayoutWithBehavior(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public static class Behavior extends android.support.design.widget.CoordinatorLayout.Behavior<FrameLayoutWithBehavior> {
private static final boolean SNACKBAR_BEHAVIOR_ENABLED;
private Rect mTmpRect;
private boolean mIsAnimatingOut;
private float mTranslationY;
public Behavior() {
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FrameLayoutWithBehavior child, View dependency) {
return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FrameLayoutWithBehavior child, View dependency) {
if (dependency instanceof Snackbar.SnackbarLayout) {
this.updateFabTranslationForSnackbar(parent, child, dependency);
} else if (dependency instanceof AppBarLayout) {
AppBarLayout appBarLayout = (AppBarLayout) dependency;
if (this.mTmpRect == null) {
this.mTmpRect = new Rect();
}
Rect rect = this.mTmpRect;
ViewGroupUtils.getDescendantRect(parent, dependency, rect);
if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
if (!this.mIsAnimatingOut && child.getVisibility() == VISIBLE) {
this.animateOut(child);
}
} else if (child.getVisibility() != VISIBLE) {
this.animateIn(child);
}
}
return false;
}
private void updateFabTranslationForSnackbar(CoordinatorLayout parent, FrameLayoutWithBehavior fab, View snackbar) {
float translationY = 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;
}
}
private float getFabTranslationYForSnackbar(CoordinatorLayout parent, FrameLayoutWithBehavior fab) {
float minOffset = 0.0F;
List dependencies = parent.getDependencies(fab);
int i = 0;
for (int z = dependencies.size(); i < z; ++i) {
View view = (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;
}
private void animateIn(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 {
Animation anim = 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);
}
}
private void animateOut(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(new ViewPropertyAnimatorListener() {
public void onAnimationStart(View view) {
Behavior.this.mIsAnimatingOut = true;
}
public void onAnimationCancel(View view) {
Behavior.this.mIsAnimatingOut = false;
}
public void onAnimationEnd(View view) {
Behavior.this.mIsAnimatingOut = false;
view.setVisibility(View.GONE);
}
})
.start();
} else {
Animation anim = android.view.animation.AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_out);
anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
anim.setDuration(200L);
anim.setAnimationListener(new AnimationUtils.AnimationListenerAdapter() {
public void onAnimationStart(Animation animation) {
Behavior.this.mIsAnimatingOut = true;
}
public void onAnimationEnd(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;
}
}
}
简单的解决方法是将随机布局锚定到 FAB 锚定的位置,为其指定特定边距,然后将 FAB 锚定到随机布局,就像这样
<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"
/>
要将 FloatingActionButton
锚定在 AppBar
下方,如下所示:
扩展 FloatingActionButton
并覆盖 offsetTopAndBottom
:
public class OffsetFloatingActionButton extends FloatingActionButton
{
public OffsetFloatingActionButton(Context context)
{
this(context, null);
}
public OffsetFloatingActionButton(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public OffsetFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
ViewCompat.offsetTopAndBottom(this, 0);
}
@Override
public void offsetTopAndBottom(int offset)
{
super.offsetTopAndBottom((int) (offset + (getHeight() * 0.5f)));
}
}
我可以通过使用 layout_anchor
layout_anchorGravity
和一些填充来解决这个问题。锚属性允许你有一个 View
相对于另一个的位置看法。但是,它的工作方式与 RelativeLayout
的工作方式并不完全相同。更多相关内容。
layout_anchor
指定您想要的 View
应该放置在哪个 View
中(即,这个 View
应该相对于由layout_anchor
属性)。然后,layout_anchorGravity
使用典型的 Gravity 值(top
、bottom
指定当前 View
将位于相对 View
的哪一侧, center_horizontal
, 等等).
单独使用这两个属性的问题是 View
的 center 与锚点将相对于另一个 View
放置.例如,如果您指定将 FloatingActionButton
锚定到 TextView
的底部,最终真正发生的是 FAB 的 center 是沿着 TextView
的底部边缘放置。
为了解决这个问题,我对 FAB 应用了一些填充,足以使 FAB 的顶部边缘接触 TextView
:
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_anchor="@id/your_buttons_id_here"
android:layout_anchorGravity="bottom"
android:paddingTop=16dp" />
您可能需要增加填充才能获得所需的效果。希望对您有所帮助!
我为您推荐一个优雅的解决方案:
<android.support.design.widget.FloatingActionButton
...
android:translationY="-20dp"
...
/>
我将 app:useCompatPadding="true"
与 FAB 一起使用,一切正常。