如何使用Espresso测试视图是否重叠?
用Espresso测试视图重叠的实用方案
刚好之前也碰到过类似的动态视图重叠检测问题,先给你理清楚现有Espresso方法的局限,再聊聊你提到的索引思路,最后给个能落地的解决方案:
先说说现有方法的问题
isDisplayed():这个坑很多!它只判断视图本身是否处于可见状态、没被父容器裁剪,但哪怕被其他视图完全盖住,它还是会返回true,完全没法用来检测重叠。isCompletelyVisible():这个方法是用来判断视图是否完全在屏幕可见区域内的,适合处理可滚动列表里的项是否完全显示,但对视图间的重叠检测没帮助。noOverlaps():这个匹配器的限制太死了,只支持TextView和ImageView,其他类型的视图根本用不了。
关于「父容器索引判断」的思路
你提到的比较父容器内视图索引的想法,其实只能判断绘制层级——索引靠后的视图会绘制在前面的视图之上,但这不能直接证明两个视图存在重叠区域。比如两个索引不同的视图可能在布局上完全不挨边,根本不会重叠。所以这个思路只能作为辅助判断,没法单独用来检测重叠。
针对动态无ID视图的解决方案
既然视图是动态创建没给ID的,我们可以通过视图的其他特征(比如类型、位置、内容)来匹配,再自定义一个Espresso匹配器,通过对比视图的边界矩形来检测重叠:
自定义重叠检测匹配器代码示例
fun doesOverlapWith(otherViewMatcher: Matcher<View>): Matcher<View> { return object : BoundedMatcher<View, View>(View::class.java) { private var targetView: View? = null override fun describeTo(description: Description) { description.appendText("overlaps with view matching: ") otherViewMatcher.describeTo(description) } override fun matchesSafely(currentView: View): Boolean { if (targetView == null) { // 从根视图中找到匹配的目标视图 targetView = findMatchingView(otherViewMatcher, currentView.rootView) if (targetView == null) return false } // 获取两个视图的全局可见矩形 val currentRect = Rect() currentView.getGlobalVisibleRect(currentRect) val targetRect = Rect() targetView!!.getGlobalVisibleRect(targetRect) // 判断矩形是否有交集(即是否重叠) return Rect.intersects(currentRect, targetRect) } private fun findMatchingView(matcher: Matcher<View>, rootView: View): View? { val viewQueue = LinkedList<View>() viewQueue.add(rootView) while (viewQueue.isNotEmpty()) { val view = viewQueue.poll() if (matcher.matches(view)) { return view } if (view is ViewGroup) { for (i in 0 until view.childCount) { viewQueue.add(view.getChildAt(i)) } } } return null } } }
使用示例
比如你要检测某个动态创建的Button和带有“Submit”文本的视图是否重叠:
onView(withClassName(`is`(Button::class.java.name))) .check(matches(doesOverlapWith(withText("Submit"))))
如果需要检测某个视图是否被任何同级视图重叠,可以再扩展一个匹配器,遍历父容器内的所有子视图,逐个对比矩形交集即可。
内容的提问来源于stack exchange,提问作者mbmc
相关产品推荐
相关产品推荐

