【发布时间】:2014-08-20 17:09:07
【问题描述】:
是否有滚动到屏幕上尚不可见的非列表视图项目的通用方法?
在没有任何预防措施的情况下,Espresso 将指示“在层次结构中找不到与 id 匹配的视图.....
我找到了这个答案……这是最好的方法吗?
onView( withId( R.id.button)).perform( scrollTo(), click());
【问题讨论】:
是否有滚动到屏幕上尚不可见的非列表视图项目的通用方法?
在没有任何预防措施的情况下,Espresso 将指示“在层次结构中找不到与 id 匹配的视图.....
我找到了这个答案……这是最好的方法吗?
onView( withId( R.id.button)).perform( scrollTo(), click());
【问题讨论】:
根据scrollTo JavaDoc,要使用您指定的代码 (onView( withId( R.id.button)).perform( scrollTo(), click());),前提条件是:“必须是 ScrollView 的后代”和“必须将可见性设置为 View.VISIBLE”。如果是这样的话,那就没问题了。
如果它在AdapterView 中,那么您应该改用onData。在某些情况下,如果您的 AdapterView 表现不佳,您可能必须实现 AdapterViewProtocol。
如果它既不在AdapterView 中,也不是ScrollView 的子代,那么您必须实现自定义ViewAction。
【讨论】:
如果您在android.support.v4.widget.NestedScrollView 内部有视图而不是scrollView,则scrollTo() 不起作用。
为了工作,您需要创建一个实现ViewAction 的类,就像ScrollToAction 但允许NestedScrollViews:
public Matcher<View> getConstraints() {
return allOf(
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE),
isDescendantOfA(anyOf(
isAssignableFrom(ScrollView.class),
isAssignableFrom(HorizontalScrollView.class),
isAssignableFrom(NestedScrollView.class))
)
);
}
额外提示并访问以下操作:
public static ViewAction betterScrollTo() {
return actionWithAssertions(new AllScrollViewsScrollToAction());
}
但是通过这个滚动它不会触发来自布局管理器的事件。
【讨论】:
对我有用的代码是:
ViewInteraction tabView = onView(allOf(
childAtPosition(childAtPosition(withId(R.id.bottomControlTabView), 0), 1),
isDisplayed()));
tabView.perform(click());
tabView.perform(click());
public static Matcher<View> childAtPosition(final Matcher<View> parentMatcher,
final int position) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("Child at position " + position + " in parent ");
parentMatcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
ViewParent parent = view.getParent();
return parent instanceof ViewGroup && parentMatcher.matches(parent)
&& view.equals(((ViewGroup) parent).getChildAt(position));
}
};
}
【讨论】:
如果视图是 ScrollView、HorizontalScrollView 或 ListView 的后代,代码 onView( withId( R.id.button)).perform( scrollTo(), click()); 将起作用。
如果我们有 NestedScrollView 而不是 ScrollView 并且对于那些不想查看 ScrollToAction 类代码的人,我编写了示例。
作为 Bruno Oliveira said,我们可以这样做:
class ScrollToActionImproved : ViewAction {
override fun getConstraints(): Matcher<View> {
return allOf(
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE),
isDescendantOfA(
anyOf(
isAssignableFrom(ScrollView::class.java),
isAssignableFrom(HorizontalScrollView::class.java),
isAssignableFrom(NestedScrollView::class.java)
)
)
)
}
override fun getDescription(): String = "scroll to view"
override fun perform(uiController: UiController?, view: View?) {
if (isDisplayingAtLeast(90).matches(view)) {
//View is already displayed
return
}
val rect = Rect()
view!!.getDrawingRect(rect)
if (!view.requestRectangleOnScreen(rect, true)) {
//Scrolling to view was requested, but none of the parents scrolled.
}
uiController!!.loopMainThreadUntilIdle()
if (!isDisplayingAtLeast(90).matches(view)) {
throw PerformException.Builder()
.withActionDescription(this.description)
.withViewDescription(HumanReadables.describe(view))
.withCause(
RuntimeException(
"Scrolling to view was attempted, but the view is not displayed"
)
)
.build()
}
}
}
并像这样使用它:
fun scrollToImproved(): ViewAction =
actionWithAssertions(ScrollToActionImproved())
/* some logic */
onView(withId(R.id.button)).perform(scrollToImproved())
它应该可以工作。
【讨论】: