当单行 Snackbar 被刷掉时,FAB 没有动画
Posted
技术标签:
【中文标题】当单行 Snackbar 被刷掉时,FAB 没有动画【英文标题】:FAB not animated when one-line Snackbar is swiped away 【发布时间】:2016-07-29 13:39:42 【问题描述】:我有一个支持FloatingActionButton
的CoordinatorLayout
,我想在其中显示一个Snackbar
..
<android.support.design.widget.CoordinatorLayout
android:id="@+id/rootView"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_>
<RelativeLayout
android:layout_
android:layout_>
...
</RelativeLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_add_field"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_
android:layout_
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/margin_default"
android:layout_marginBottom="@dimen/profile_floating_margin_bottom"
android:layout_marginRight="@dimen/profile_floating_margin_right"
android:clickable="true"
android:src="@drawable/icon_plus"
app:backgroundTint="@color/brand_green"
app:borderWidth="0dp"
app:elevation="@dimen/fac_icon_elevation"/>
</android.support.design.widget.CoordinatorLayout>
现在我正在展示这样的 Snackbar
Snackbar.make(mRootView, "Something went wrong", Snackbar.LENGHT_SHORT)
.show();
当它显示时,FAB 向上滑动,当它(在 LENGHT_SHORT 之后)消失时,FAB 向下滑动,一切正常。
但是,如果我将 Snackbar 滑开,FAB 会向下移动而没有幻灯片动画。它只是闪烁到它的初始位置。
有趣的是,如果 Snackbar 有两条线(无论它是否有动作)并且被滑开,FAB 会以通常的滑动动画正确地动画回到它的位置。
这是android.support.design.widget.CoordinatorLayout
中的错误吗?
或android.support.design.widget.FloatingActionButton
?有什么解决方法吗?
【问题讨论】:
你解决了这个问题吗? 【参考方案1】:不使用基于Matteo Destro's post 的ValueAnimator
的Kotlin 解决方案:
class SnackBarAwareBehavior : CoordinatorLayout.Behavior<View>
companion object
private const val DURATION = 180
constructor() : super()
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun layoutDependsOn(
parent: CoordinatorLayout,
child: View,
dependency: View
): Boolean
return dependency is Snackbar.SnackbarLayout
override fun onDependentViewChanged(
parent: CoordinatorLayout,
child: View,
dependency: View
): Boolean
if (dependency.visibility == View.VISIBLE)
moveChildUp(child, dependency.height + dependency.marginBottom)
return true
return false
override fun onDependentViewRemoved(parent: CoordinatorLayout, child: View, dependency: View)
moveChildToInitialPosition(child)
private fun moveChildUp(child: View, translation: Int)
child.animate()
.translationY((-translation).toFloat())
.setInterpolator(DecelerateInterpolator())
.setDuration(DURATION.toLong())
.start()
private fun moveChildToInitialPosition(child: View)
child.animate()
.translationY(0f)
.setInterpolator(AccelerateInterpolator())
.setDuration(DURATION.toLong())
.start()
【讨论】:
【参考方案2】:我最近遇到了同样的问题,我最终为 FAB 创建了一个自定义布局行为类,以便在轻扫小吃栏时执行动画。
创建这个类:
public class SnackbarAwareBehavior extends CoordinatorLayout.Behavior<View>
private static final int ANIMATION_DURATION = 180;
public SnackbarAwareBehavior()
super();
public SnackbarAwareBehavior(Context context, AttributeSet attrs)
super(context, attrs);
@Override
public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency)
return dependency instanceof Snackbar.SnackbarLayout;
@Override
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency)
if (dependency.getVisibility() == View.VISIBLE)
// Change the translation of the FAB only if the snackbar is visible
child.setTranslationY(dependency.getTranslationY() - getTranslationYBottom(dependency));
return true;
return false;
@Override
public void onDependentViewRemoved(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency)
if (dependency.getVisibility() == View.VISIBLE)
child.setTranslationY(0f);
else
// Execute the animation only if the snackbar has been swiped away, i.e. when it's not visible
ValueAnimator animator = new ValueAnimator();
animator.setFloatValues(child.getTranslationY(), 0f);
animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
animator.setDuration(ANIMATION_DURATION);
animator.addUpdateListener(animation -> child.setTranslationY((float) animation.getAnimatedValue()));
animator.start();
private int getTranslationYBottom(View view)
// Get the translation position of the snackbar when it's hidden.
// Method taken from BaseTransientBottomBar.Behavior class.
int translationY = view.getHeight();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
if (layoutParams instanceof ViewGroup.MarginLayoutParams)
translationY += ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;
return translationY;
然后在你的布局中:
<android.support.design.widget.FloatingActionButton
...
app:layout_behavior="your.package.SnackbarAwareBehavior">
【讨论】:
以上是关于当单行 Snackbar 被刷掉时,FAB 没有动画的主要内容,如果未能解决你的问题,请参考以下文章
在 CoordinatorLayout 中安排一个 BottomNavigationView、一个 FAB 和一个 FrameLayout 并使其与 Snackbar 一起使用