Snackbar and other animations stopped working on s

2019-03-08 19:54发布

I have a very odd issue that I cannot figure out. I was not an issue until recently but I can't seem to revert back to prevent it. Also the other odd thing is it works on some devices and others it does not.

The issue is animations. One in particular is snack bar. The snackbar should animate up and down but it is not. it just shows then hides. check video below to see issue.

Video of issue

Here is the Android code to animate the snackbar in

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        ViewCompat.setTranslationY(mView, mView.getHeight());
        ViewCompat.animate(mView)
                .translationY(0f)
                .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
                .setDuration(ANIMATION_DURATION)
                .setListener(new ViewPropertyAnimatorListenerAdapter() {
                    @Override
                    public void onAnimationStart(View view) {
                        mView.animateChildrenIn(ANIMATION_DURATION - ANIMATION_FADE_DURATION,
                                ANIMATION_FADE_DURATION);
                    }

                    @Override
                    public void onAnimationEnd(View view) {
                        onViewShown();
                    }
                }).start();
    }

Its using ViewCompat for the v4 Library. I have other animations working in another activity working fine. Also the issue is not on just one activity its all of them. That makes me think its system wide somehow. But they all use different internal themes but all extend Theme.AppCompat.NoActionBar.

Here is my main layout

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:elevation="4dp">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:titleTextAppearance="@style/ToolbarTitle"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:layout_scrollFlags="scroll|enterAlways|snap"/>

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabTextAppearance="@style/TabText"
        app:tabMinWidth="@dimen/tab_minwidth"
        app:tabMode="fixed"
        app:tabGravity="fill"
        app:layout_scrollFlags="enterAlways"/>


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

<FrameLayout
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

<fr.castorflex.android.circularprogressbar.CircularProgressBar
    android:id="@+id/base_progressSpinner"
    android:layout_gravity="center"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:indeterminate="true"
    android:visibility="invisible"
    app:cpb_color="@color/spinner"
    app:cpb_rotation_speed="1.0"
    app:cpb_sweep_speed="1.0"
    app:cpb_stroke_width="4dp"
    app:cpb_min_sweep_angle="10"
    app:cpb_max_sweep_angle="300"/>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab_upload"
    android:visibility="gone"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    app:layout_anchor="@id/content_frame"
    app:layout_anchorGravity="bottom|right|end"
    app:borderWidth="0dp"
    android:src="@drawable/app_fab_upload"
    android:layout_margin="@dimen/big_padding"
    android:clickable="true"
    app:backgroundTint="@color/fab_social"/>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab_muzei"
    android:visibility="gone"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    app:layout_anchor="@id/content_frame"
    app:layout_anchorGravity="bottom|right|end"
    app:borderWidth="0dp"
    android:src="@drawable/app_fab_muzei"
    android:layout_margin="@dimen/big_padding"
    android:clickable="true"
    app:backgroundTint="@color/fab_social"/>

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

Devices it works on

  • Nexus 9 (Marshmallow)
  • Nexus 4 (KitKat)
  • Galaxy S7 (Marshmallow)

Devices it does not work

  • Droid Turbo 2 (Marshmallow)
  • Galaxy S7 (Marshmallow) *my device works, my testers does not
  • Nexus 6p (Android N)

The other animation issues are with Switches. I have 2 in same layout and one stutters when switched and the other just switches with no animation.

I also have a LayoutTransition set to my AppBarLayout to animation the hiding/showing of my TabLayout and it works fine and all devices

3条回答
放荡不羁爱自由
2楼-- · 2019-03-08 20:39

As Bignadad mentioned, the problem is that any accessibility feature, including things like password managers, disables the snackbar animations. Google, as of this edit, has fixed this for AndroidX but not the Design support library

Because Snackbar's base class, BaseTransientBottomBar, handles the animation, with package private, final methods, you have two choices if you want to fix it: roll your own snackbar from scratch, or use a more hacky solution with reflection:

Kotlin example:

// Only force when necessary, and don't animate when TalkBack or similar services are enabled
val shouldForceAnimate = !accessibilityManager.isEnabled && accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty()

Snackbar.make(coordinatorLayout, text, duration).apply {
    if (shouldForceAnimate) {
        try {
            val accManagerField = BaseTransientBottomBar::class.java.getDeclaredField("mAccessibilityManager")
            accManagerField.isAccessible = true
            val accManager = accManagerField.get(this)
            AccessibilityManager::class.java.getDeclaredField("mIsEnabled").apply {
                isAccessible = true
                setBoolean(accManager, false)
            }
            accManagerField.set(this, accManager)
        } catch (e: Exception) {
            Log.d("Snackbar", "Reflection error: $e")
        }
    }
}.show()

Java example:

// Only force when necessary, and don't animate when TalkBack or similar services are enabled
boolean shouldForceAnimate = !accessibilityManager.isEnabled() && accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN).size == 0;

Snackbar snackbar = Snackbar.make(coordinatorLayout, text, duration);
if(shouldForceAnimate){
    try {
        Field accManagerField = BaseTransientBottomBar.class.getDeclaredField("mAccessibilityManager");
        accManagerField.setAccessible(true);
        AccessibilityManager accManager = (AccessibilityManager) accManagerField.get(snackbar);
        Field isEnabledField = AccessibilityManager.class.getDeclaredField("mIsEnabled");
        isEnabledField.setAccessible(true);
        isEnabledField.setBoolean(accManager, false);
        accManagerField.set(snackbar, accManager);
    } catch (Exception e) {
        Log.d("Snackbar", "Reflection error: " + e.toString());
    }
}
snackbar.show();

I'd love a third option here, but I'm not aware of one, at least until AndroidX gets out of beta with the proper fix.

查看更多
来,给爷笑一个
3楼-- · 2019-03-08 20:40

I found the reason why this is happening, but not how to fix yet.

/**
 * Returns true if we should animate the Snackbar view in/out.
 */
private boolean shouldAnimate() {
    return !mAccessibilityManager.isEnabled();
}

That is called by Snackbar class and is false on working devices, and true on devices not working. Does anyone know about this?

So after i disabled lastpass in my system settings, accessibility the snackbar now animates as it should. That is crazy how that works. Nova launcher has the same affect. I guess any service in accessibility that is enabled will cause the snackbar animation to not work.

查看更多
等我变得足够好
4楼-- · 2019-03-08 20:49

This has been fixed since Material Components for Android 1.0.0-alpha3 with this commit.

Use it instead of the Design Library (which is the way to go if you're using AndroidX):

implementation "com.google.android.material:material:$material_components_version"
查看更多
登录 后发表回答