Add a TextView above a FloatingActionButton

今天在微博上看到Mr_Wrong丶同学提了个问题,问题指向了这里How to add a TextView above a FloatingActionButton in Android 。问题描述看下图,大致来说就是 FloatingActionButton 遮住了本该显示在上层的 TextView

下面有人给了解决方案,给 TextView 添加属性 android:elevation="7dp" ,乍一看,哇,好神奇,一个属性就完美解决了整个问题。那到底是为什么呢?(注意,Elevation 只能用在 API19 以上。)

仅仅是添加了 elevation 属性就 OK 了,要整明白为什么,就得先去看看 API 里这个 elevation 到底是什么意思。

大致就是说 elevation 是 view 在 Z 轴上的位置,可以用一个浮点数加长度的单位来表示,一般情况下应该是 dp(这里的 sp 个人觉着应该是不对的)。

在处理这个之前,首先我们需要了解一个概念,组件在 Z 轴上的高度等于 translationZ + elevation

首先,我们看这个问题,TextView 被 FloatingActionButton 覆盖了。这只说明一个问题:FloatingActionButton 一定是在 Z 轴上有默认的高度的,因为是同是 Z 轴的值,只有当 FloatingActionButton 在 Z 轴的高度大于 TextView 在 Z 轴的高度时,TextView 才会出现 TextView 被覆盖的情况。而在帧布局里后添加的组件会覆盖在先添加的组件上,如果 TextView 和 FloatingActionButton 在 Z 轴上的位置一样的话,TextView 就会显示在 FloatingActionButton 上了。这样我们就可以先打印出 translationZelevation 的默认值。

1
2
3
4
float elevation = fab.getElevation();
Toast.makeText(this, elevation + "", Toast.LENGTH_SHORT).show();
float fabTranslationZ = fab.getTranslationZ();
Toast.makeText(this, fabTranslationZ + "", Toast.LENGTH_SHORT).show();

我用的测试机是小米2sc,得到的 elevation 值是 12.0 ,fabTranslationZ 的值是 0.0 。因为手机分辨率是 720P,所以这个 elevation 默认值就是 6dp ,fabTranslationZ 默认值是 0dp 。

那样,这样是不是就彻底解决我们的问题了呢?答案是:否!以内即便设置了 android:elevation="6dp",正常显示 TextView 不会被覆盖,但是当我们点击按压 FloatingActionButton 的时候,ripple 散开,这个 TextView 还是会覆盖掉。所以说这样处理并不完美。因为是点击按压的时候出现了问题,那我们就再看 FloatingActionButton 是否有相关的属性,刚好就有一个 app:pressedTranslationZ 属性,而它也是有默认值的,当我们把它的值设置为 0dp 时,就完美解决了按压时被覆盖的问题。

既然明确了上面的结论,那接下来处理就非常简单了。终极的解决方案就是:设置 FloatingActionButton 的默认阴影为 0dp ,app:elevation="0dp";因为 fabTranslationZ 默认值是 0dp ,所以不用管;然后设置 app:pressedTranslationZ 的值为 0dp ,app:pressedTranslationZ="0dp" ,来保证按压时 TextView 不被覆盖。(这样做牺牲了好多其他的效果,还是不完美…)

最后我们来看一看关于 FloatingActionButton 的默认值 dimens.xml ,验证一下我们的设置。当然还要感谢Mr_Wrong丶同学帮我一起来验证解决问题。