【问题标题】:Android - Espresso - scrolling to a non-list View itemAndroid - Espresso - 滚动到非列表查看项目
【发布时间】:2014-08-20 17:09:07
【问题描述】:

是否有滚动到屏幕上尚不可见的非列表视图项目的通用方法?

在没有任何预防措施的情况下,Espresso 将指示“在层次结构中找不到与 id 匹配的视图.....

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

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

【问题讨论】:

    标签: android android-espresso


    【解决方案1】:

    根据scrollTo JavaDoc,要使用您指定的代码 (onView( withId( R.id.button)).perform( scrollTo(), click());),前提条件是:“必须是 ScrollView 的后代”和“必须将可见性设置为 View.VISIBLE”。如果是这样的话,那就没问题了。

    如果它在AdapterView 中,那么您应该改用onData。在某些情况下,如果您的 AdapterView 表现不佳,您可能必须实现 AdapterViewProtocol

    如果它既不在AdapterView 中,也不是ScrollView 的子代,那么您必须实现自定义ViewAction

    【讨论】:

    • "它既不在 AdapterView 也不在 ScrollView 的子视图中" 例如。 NestedScrollView 您可以添加 Barista 依赖项并使用休闲方法:scrollTo(R.id.); github.com/SchibstedSpain/Barista#baristas-assertions-api
    • 其实它比只有 ScrollView 的要好一些。查看 ScrollToAction 的实现(scrollTo() 返回的 ViewAction),Horizo​​ntalScrollView 和 ListView 也是支持的。 git.io/fh7LO
    【解决方案2】:

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

    但是通过这个滚动它不会触发来自布局管理器的事件。

    【讨论】:

      【解决方案3】:

      对我有用的代码是:

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

      【讨论】:

        【解决方案4】:

        如果视图是 ScrollView、Horizo​​ntalScrollView 或 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())
        

        它应该可以工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多