Espresso嵌套RecyclerView精准滑动定位目标item并点击的实现问题
嵌套RecyclerView精准滚动定位解决方案
问题根因
你之前的方案存在两个核心问题:
- 用全局
swipeUp()单次滚动距离太大,必然容易滑过目标item,且repeatedlyUntil默认会先执行一次滑动再判断条件,即使目标已经在可视区也会触发滑动 nestedScrollTo()只适用于子view放在NestedScrollView下的场景,嵌套RecyclerView场景不满足约束,所以抛出异常
解决思路
不要手动控制滑动距离,直接用Espresso RecyclerView库自带的scrollTo系列API,它会自动计算滚动距离,只滚到刚好目标item可见的位置,不会滑过。因为是双层嵌套RecyclerView,需要先滚动父RecyclerView到包含目标item的子RecyclerView所在父项,再滚动子RecyclerView到目标item。
实现代码
首先确保你已经引入了和当前Espresso版本匹配的espresso-contrib依赖,否则无法使用RecyclerViewActions相关API。
1. 适配ViewHolder匹配逻辑
// 匹配包含指定文本的ViewHolder fun withItemContainingText(targetText: String): BoundedMatcher<RecyclerView.ViewHolder, RecyclerView.ViewHolder> { return object : BoundedMatcher<RecyclerView.ViewHolder, RecyclerView.ViewHolder>(RecyclerView.ViewHolder::class.java) { override fun describeTo(description: Description) { description.appendText("ViewHolder containing text: $targetText") } override fun matchesSafely(holder: RecyclerView.ViewHolder): Boolean { val matchedViews = ArrayList<View>() holder.itemView.findViewsWithText(matchedViews, targetText, View.FIND_VIEWS_WITH_TEXT) return matchedViews.isNotEmpty() } } } // 匹配父RecyclerView中包含目标文本的子RecyclerView所在的父项 fun parentItemHasTargetText(targetText: String): BoundedMatcher<RecyclerView.ViewHolder, RecyclerView.ViewHolder> { return object : BoundedMatcher<RecyclerView.ViewHolder, RecyclerView.ViewHolder>(RecyclerView.ViewHolder::class.java) { override fun describeTo(description: Description) { description.appendText("Parent item contains child view with text: $targetText") } override fun matchesSafely(holder: RecyclerView.ViewHolder): Boolean { val childRecycler = holder.itemView.findViewById<RecyclerView>(R.id.recycler_list) ?: return false val matchedViews = ArrayList<View>() childRecycler.findViewsWithText(matchedViews, targetText, View.FIND_VIEWS_WITH_TEXT) return matchedViews.isNotEmpty() } } }
2. 执行滚动+点击逻辑
val targetText = "你要匹配的目标文本" // 第一步:滚动父RecyclerView到包含目标文本的父项,确保对应子RecyclerView可见 Espresso.onView(ViewMatchers.withId(R.id.parent_recycler_list)) .perform( RecyclerViewActions.scrollToHolder(parentItemHasTargetText(targetText)) ) // 第二步:滚动对应子RecyclerView到目标item,再执行点击 Espresso.onView( CoreMatchers.allOf( ViewMatchers.withId(R.id.recycler_list), ViewMatchers.hasDescendant(ViewMatchers.withText(targetText)) ) ).perform( RecyclerViewActions.actionOnHolderItem( withItemContainingText(targetText), ViewActions.click() ) )
特殊场景适配
如果你的子RecyclerView已经关闭了滚动功能,不需要执行第二步的子列表滚动,父列表滚动完成后直接匹配目标文本点击即可。
内容的提问来源于stack exchange,提问作者Adam Schultz
相关产品推荐
相关产品推荐

