Android - Espresso - 滚动到非列表查看项目

时间:2014-08-20 17:09:08

标签: android android-espresso

是否有滚动到非列表的常规方法查看屏幕上尚未显示的项目?

如果没有任何预防措施,Espresso将指示“层次结构中没有视图与id相匹配.....

我找到了这个答案......这是最好的方法吗?

onView( withId( R.id.button)).perform( scrollTo(), click());

4 个答案:

答案 0 :(得分:20)

根据scrollTo JavaDoc,要使用您指定的代码(onView( withId( R.id.button)).perform( scrollTo(), click());),前提是:"必须是ScrollView的后代"和"必须将可见性设置为View.VISIBLE"。如果是这种情况,那就可以了。

如果它位于AdapterView,那么您应该使用onData。在某些情况下,如果AdapterViewProtocol表现不佳,则可能必须实施AdapterView

如果它既不是AdapterView也不是ScrollView的孩子,那么您必须实施自定义ViewAction

答案 1 :(得分:3)

如果你在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());
}

但是使用此滚动条不会触发布局管理器中的事件。

答案 2 :(得分:0)

对我有用的代码是:

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));
            }
        };
    }

答案 3 :(得分:0)

如果视图是 ScrollView、Horizo​​ntalScrollView 或 ListView 的后代,代码 <svg attr.height="{{radius * 2}}" attr.width="{{radius * 2}}" > <defs> <lineargradient id="grad" x1="0" y1="0" x2="1" y2="1"> <stop offset="15%" stop-color="#FFF" stop-opacity="1"></stop> <stop offset="85%" stop-color="#000" stop-opacity="1"></stop> </lineargradient> </defs> <circle class="gauge_base" attr.cx="{{radius}}" attr.cy="{{radius}}" stroke="gray" attr.r="{{innerRadius}}" stroke-width="6px" attr.transform="{{transform}}" stroke-linecap="round" fill="transparent" attr.stroke-dasharray="{{dashArray}}" /> <circle class="gauge_pourcentage" attr.cx="{{radius}}" attr.cy="{{radius}}" attr.r="{{innerRadius}}" stroke="url(#grad)" attr.stroke-dasharray="{{dashArray}}" stroke-width="12px" attr.stroke-dashoffset="{{offset}}" attr.transform="{{transform}}" style="transition: stroke-dashoffset 0.3s" stroke-linecap="round" fill="transparent" /> </svg> 将起作用。

如果我们有 onView( withId( R.id.button)).perform( scrollTo(), click()); 而不是 NestedScrollView 并且对于那些不想查看 ScrollView 类代码的人,我编写了示例。

作为 Bruno Oliveira said,我们可以这样做:

ScrollToAction

}

像这样使用它:

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()
    }
}

它应该可以工作。