Snackbar and other animations stopped working on some Android devices

前端 未结 3 570
情书的邮戳
情书的邮戳 2021-01-31 18:12

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

3条回答
  •  野性不改
    2021-01-31 19:01

    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.

提交回复
热议问题