Reputation: 7601
Is there a general approach for scrolling to non-list View items that are not yet visible on the screen?
Without any precautions, Espresso will indicate that "No Views in hierarchy found matching with id .....
I found this answer ... is this the best approach?
onView( withId( R.id.button)).perform( scrollTo(), click());
Upvotes: 12
Views: 22427
Reputation: 66
The code onView( withId( R.id.button)).perform( scrollTo(), click());
will work if the view is descendant of ScrollView, HorizontalScrollView or ListView.
If we have NestedScrollView
instead of ScrollView
and for those who don't want to look into ScrollToAction
class code I wrote the sample.
As Bruno Oliveira said we can do something like this:
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()
}
}
}
And use it like this:
fun scrollToImproved(): ViewAction =
actionWithAssertions(ScrollToActionImproved())
/* some logic */
onView(withId(R.id.button)).perform(scrollToImproved())
It should work.
Upvotes: 1
Reputation: 177
Code that worked for me is:
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));
}
};
}
Upvotes: 0
Reputation: 265
If you have a view inside android.support.v4.widget.NestedScrollView
instead of scrollView
scrollTo()
does not work.
In order to work you need to create a class that implements ViewAction
just like ScrollToAction
but allows NestedScrollView
s:
public Matcher<View> getConstraints() {
return allOf(
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE),
isDescendantOfA(anyOf(
isAssignableFrom(ScrollView.class),
isAssignableFrom(HorizontalScrollView.class),
isAssignableFrom(NestedScrollView.class))
)
);
}
extra tip and access the action like:
public static ViewAction betterScrollTo() {
return actionWithAssertions(new AllScrollViewsScrollToAction());
}
But with this scroll it does not trigger events from the layout managers.
Upvotes: 4
Reputation: 3065
According to the scrollTo
JavaDoc, to use the code you specified ( onView( withId( R.id.button)).perform( scrollTo(), click());
), the preconditions are: "must be a descendant of ScrollView" and "must have visibility set to View.VISIBLE
". If that is the case, then that will work just fine.
If it is in an AdapterView
, then you should use onData
instead. In some cases, you may have to implement the AdapterViewProtocol
, if your AdapterView
is not well behaved.
If it is neither in an AdapterView
nor a child of a ScrollView
, then you would have to implement a custom ViewAction
.
Upvotes: 24