一、今天在做NavigatorBar(导航栏,系统级应用)时,遇到一个问题,在调用TextView.setText方法后,会出现文本重叠的问题,如下图所示:

二、我的实现场景比较特殊,我的导航栏是无Activity做为容器的,在Service中,直接通过WindowManager.addView()添加NavigatorBar,而NavigatorBar本身是一个自定义View,直接继承自FrameLayout实现的。所以,我的NavigatorBar的getParent()返回的是ViewRootImpl,而不是传统的DecorView。
我的整体排查思路如下:
- TextView的实例是否有过变化?,经log查看,确实是同个实例。
- 是否有2个TextView存在,导致重叠? 经log查看,只有一个TextView。
- 在setText之后,打印text,看看打出来的text是不是最新的?经log查看,是最新的text,出现重叠是旧的text没被清除而留下来的残影。
- 调用invalidate()方法,有效? 不起作用。
- 尝试调用WindowManager的updateViewLayout,不起作用。(除非修改长宽,但这个会导致闪烁,用户体验不佳)
- 改成动态添加TextView,每次设置文本,都先remove现有的,再创建个新的。结果,仍然不起作用。
- 在网上搜索相同问题,查出来的文章,有的说,给根布局设置背景,比如,这篇:Android 绘制产生重影(重叠)。后面,经实验,设置个非透明的颜色,比如黑色,白色,都可以,但透明、半透明、不设置,都不行。如果可以给根布局设置纯色背景,那问题到此可以解决。
- 但像我这种业务场景的话就不行,原因是一旦某个app设置了跟我背景色不一致的颜色,就会出现颜色相左的问题 【详见图1】 ,如图所示,一条黑条横在页面中间。既然不行,那就继续排查。

- 重新屡了一下思路: 首先,Navigator是自定义View。自定义View就会走onDraw(),那么,我是不是可以考虑在onDraw里面做什么清除操作,或者自已绘制文本,不用TextView,就没这问题了?然后,我就重写Navigator(FrameLayout的子类)的onDraw()方法,并加log。但发现,onDraw方法,并没有被触发。后面,想起来,以前做继承自ViewGroup的自定义View时,也遇到过onDraw没被调用过,原因是ViewGroup默认是不触发draw的,源码如下所示:
// 摘自 ViewGroup。
private void initViewGroup() {
// ViewGroup doesn't draw by default
if (!isShowingLayoutBounds()) {
setFlags(WILL_NOT_DRAW, DRAW_MASK);
}
.... 省略其它
}
- FrameLayout直接继承自ViewGroup,默认也是没有调onDraw方法。问题搞清楚了,我们现在只需要加这行代码,就可以触发ViewGroup/FrameLayout/NavigatorBar的onDraw()方法:
// 摘自 NavigatorBar
init {
setWillNotDraw(false)
}
- 现在,NavigatorBar的onDraw方法有触发了,但重叠问题仍然存在。此时,我第一个猜想是,这个重叠,既然是个残影,即上个绘制没有被清空导致的。那我加上清空画布的代码,是不是就OK了?然后,我就在onDraw方法里面加上清空画布的代码,如下所示:
// 摘自 NavigatorBar
override fun onDraw(canvas: Canvas)

本文讲述了作者在Android系统级应用中遇到的TextView重叠问题,通过自定义View和onDraw方法、清空画布以及设置WindowManager背景透明,最终解决了在无Activity容器的Service中添加导航栏时的文本重叠问题。
最低0.47元/天 解锁文章
2049

被折叠的 条评论
为什么被折叠?



