在我们的一个应用中有一个功能是需要显示时间的秒数分钟数等 , 正常的逻辑中 , 就是每秒去更新一次 Text View 的 set Text() 从而实现数据的显示 。 而当我们需要这个 TextVIew 能够移动时 , 却发现移动后每秒 TextVIew 都会重制位置
通过堆栈日志分析 , TextVIew 的 requestLayout 每秒都会被调用 , 再深入看 , 发现就是 set Text () 方法调用的
让我们看一下源码:

这其中的重点是第一:设置mPrivateFlags标记为需要重新layout,当下次View刷新周期到时,会触发其onMeasure和onLayout等方法进行布局计算;第二:调用其parent的requestLayout方法,即触发其父View也进行布局重计算。
到这里就知道为什么位置会被刷新了,如果调用子view的requestLayout进行布局重计算,其也会调用父View的requestLayout,一层一层传上去,直到rootView。
再回到我们遇到的问题,我们并没有直接调用requestLayout,而是调用了setText,setBackgroundDrawable这些方法,看来这些方法里面可能也调用了requestLayout从而导致其parent也进行了布局重计算。
于是我看了下setText方法,在里面发现了一行在之前排查堆栈信息时看到的关键的代码:checkForRelayout方法

点进去可以看到:

当View的LayoutParams是WRAP_CONTENT时,TextView会走到if中,在这里面涉及到了View的计算宽高,最后会调用到invalidate()和requestLayout()方法,也就是造成我们遇到的问题的罪魁祸首
看到这里时在想解决方法,想了几个思路
1、在 requestLayout调用后恢复View的位移信息
2、避免调用到 requestLayout
第一个方法,明显有种堆屎山的嫌疑,在TextView异常加载的基础上又额外的去加载位移操作,所以我把目光放在第二个点上,如何避免调用 requestLayout,按照源码中的逻辑,就是避免Text View的LayoutParams是WRAP_CONTEN
这样子又有两种思路
1、自定义TextView,手动判断以及设置TextView的宽高
2、修改布局,将宽度写死或者设置mach
在查看布局后选择第二种方案,因为我用的是约束布局,当我的TextView只设置了 layout_constraintStart_toStartOf或者 layout_constraintEnd_toEndOf,这时 WRAP_CONTEN和MACH _CONTEN其实效果一样
而在同时设置了 layout_constraintStart_toStartOf和 layout_constraintEnd_toEndOf的方案中,可以外面嵌套一层线下布局,让TextView在线性布局中设为 MACH _CONTEN即可解决问题
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69917874/viewspace-3015401/ ,如需转载,请注明出处,否则将追究法律责任。