解决SnackBar无动画现象

更新(2018年10月22日)

在新的material-components-android库中(版本号:1.0.0-alpha3),已经修复了这个bug,support库中的Snackbar依旧存在这个问题,此篇文章仅供参考使用。感谢 Trumeet 的提醒。
以下为原文:

发现问题

突然间不知道从什么时候开始,手机上的app只要是调用了SnackBar的地方,SnackBar显示都没有效果,这两天突然开始察觉到这个问题了,开始各种google,但是都没有找到直接让SnackBar没有动画的结果(中文),甚至我还以为是SnackBar的源码改了。
但是又觉得不对,google的这个SnackBar新控件非常不错,不应该把动画去掉啊。
为此,我特意将design包的版本回退到22.2.0版本,依旧是没有动画。
这里开始我就觉得不对了,google不可能去掉并且旧版本依旧没有动画,那么应该是我的配置上的问题。
想到这里,我开始去查看CoordinatorLayout的用法,但是依旧没有任何卵用。

解决问题

突然间我想到了一个问题,会不会是国内还没有察觉到这个问题,但是国外有了呢,我是不相信全世界就我一个人有这个问题的。
抱着试一试的态度,我开始google snackbar no animation,果不其然,找到了许多和我相同的问题。


简单的查看了一下,有的人说是开发者选项中的动画缩放(?)的问题,但是我试了依旧错误,继续看才看到一个回答是辅助功能导致的。


查看我手机上的辅助功能选项,发现打开了一个服务——冰箱的后台服务。


将这个服务关闭之后,再次打开应用,SnackBar的动画显示出来了。

说在后面

继续查看了这个问题,但是没有看出什么来,只是提供了一个方法,使用AccessibilityManager.isEnabled()来判断辅助功能是否开启,但是我在代码中添加提示错误,AccessibilityManager是一个final类,这个类中使用了单例模式,一个static方法返回实例,但是我在调用这个静态方法的时候报错,提示找不到这个方法,查看源码AccessibilityManager类是公有的,静态方法也是公有的,但是报错,不知道为什么,如果有人知道为什么的请告诉我。

2017年8月3日更新:
时间过去了五个月,今天我总算是找到了解决方法。
前面我们已经说了SnackBar没有动画是因为开启了无障碍服务,在SnackBar的父类BaseTransientBottomBar中会检测无障碍服务的开启状况,偏偏SnackBarfinal类,看起来似乎有点无解,继承SnackBar重写是肯定不行的。
幸运的是,我在StackOverFlow上找到一个解决方法,参考链接
这个方法是利用反射将AccessibilityManager类在app中调用的对象的mIsEnabled属性值改为false,这样就能通过BaseTransientBottomBar的检测,同时系统的无障碍服务并没有关闭,也不影响使用。

为了方便使用,我将这一段代码添加到了我自己的库中,这样我只需要直接在Application中初始化这样一句话就能够实现无视无障碍服务开启状况显示SnackBar的动画。以下是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
object ASnackBar
{
private val TAG = "ASnackBar"

@JvmStatic fun disableAccessibility(context: Context)
{
val contextThemeWrapper = ContextThemeWrapper(context, R.style.Theme_AppCompat)
val view = LayoutInflater.from(contextThemeWrapper).inflate(R.layout.mystery0_snack_bar_coordinator_layout, null)
Snackbar.make(view, "SnackBar", Snackbar.LENGTH_SHORT)
.apply {
try
{
val mAccessibilityManagerField = BaseTransientBottomBar::class.java.getDeclaredField("mAccessibilityManager")
mAccessibilityManagerField.isAccessible = true
val accessibilityManager = mAccessibilityManagerField.get(this)
val mIsEnabledField = AccessibilityManager::class.java.getDeclaredField("mIsEnabled")
mIsEnabledField.isAccessible = true
mIsEnabledField.setBoolean(accessibilityManager, false)
mAccessibilityManagerField.set(this, accessibilityManager)
}
catch (e: Exception)
{
Logs.e(TAG, "disableAccessibility: $e")
}
}
}
}

2018年10月22日更新:
由于上面的代码在部分定制系统会出问题,并且已经不再更新ToolsDemo库了,所以删掉以下内容,上述代码仅供参考,直接用也行(如果不怕booooooooooooom的话~)
使用时只需要这样的一行代码即可搞定,当然,前提你需要使用我的这个ToolsDemo库

1
ASnackBar.disableAccessibility(this);

参考列表

java - SnackBar appear animation - Stack Overflow
Issue 206416: Snackbar no longer slides onto screen
Snackbar and other animations stopped working on some Android devices

坚持原创技术分享,您的支持将鼓励我继续创作!