Espresso,当NestedScrollView或RecyclerView在CoordinatorLayout中时滚动不起作用

iva*_*acf 35 android android-espresso android-recyclerview coordinator-layout android-nestedscrollview

它似乎CoordinatorLayout打破了Espresso行为的行为,如scrollTo()RecyclerViewActions.scrollToPosition().

NestedScrollView问题

对于像这样的布局:

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        ...

    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        ...

    </android.support.design.widget.AppBarLayout>

</android.support.design.widget.CoordinatorLayout>
Run Code Online (Sandbox Code Playgroud)

如果我尝试滚动到NestedScrollView使用ViewActions.scrollTo()第一个问题内部的任何视图我发现是我得到了PerformException.这是因为这个动作只支持ScrollViewNestedScrollView不会扩展它.此处解释了此问题的解决方法,基本上我们可以复制代码scrollTo()并更改约束以支持NestedScrollView.这似乎有效,如果NestedScrollView它不在一个CoordinatorLayout但只要你把它放在CoordinatorLayout滚动动作失败.

RecyclerView问题

对于相同的布局,如果我替换了NestedScrollViewa RecyclerView,则滚动也存在问题.

在这种情况下,我正在使用RecyclerViewAction.scrollToPosition(position).不像NestedScrollView,在这里我可以看到一些滚动发生.但是,它看起来像滚动到错误的位置.例如,如果我滚动到最后一个位置,它会显示倒数第二个但不是最后一个.当我移动RecyclerView了的CoordinatorLayout滚动运作,因为它应该.

目前我们无法CoordinatorLayout为因此问题而使用的屏幕编写任何Espresso测试.任何遇到相同问题或知道解决方法的人?

Tur*_*ole 25

发生这种情况是因为Espresso scrollTo()方法显式检查布局类,仅适用于ScrollView和Horizo​​ntalScrollView.在内部它使用View.requestRectangleOnScreen(...)所以我希望它实际上适用于许多布局.

我对NestedScrollView的解决方法是采用ScrollToAction并修改该约束.修改后的操作适用于NestedScrollView并进行了更改.

ScrollToAction类中的已更改方法:

public Matcher<View> getConstraints() {
    return allOf(withEffectiveVisibility(Visibility.VISIBLE), isDescendantOfA(anyOf(
            isAssignableFrom(ScrollView.class), isAssignableFrom(HorizontalScrollView.class), isAssignableFrom(NestedScrollView.class))));
}
Run Code Online (Sandbox Code Playgroud)

便利方法:

public static ViewAction betterScrollTo() {
    return ViewActions.actionWithAssertions(new NestedScrollToAction());
}
Run Code Online (Sandbox Code Playgroud)

  • 你的`NestedScrollView`是在`CoordinatorLayout`里面吗?我试过这个,如果`NestedScrollView`不在`CoordinatorLayout`中,它似乎只能工作. (5认同)

tas*_*iac 14

以下是我和@miszmaniac在Kotlin做过同样的事情.随着在Kotlin的代表团,它更清洁,更容易,因为我不必覆盖我不需要的方法.

class ScrollToAction(
    private val original: android.support.test.espresso.action.ScrollToAction = android.support.test.espresso.action.ScrollToAction()
) : ViewAction by original {

  override fun getConstraints(): Matcher<View> = anyOf(
      allOf(
          withEffectiveVisibility(Visibility.VISIBLE),
          isDescendantOfA(isAssignableFrom(NestedScrollView::class.java))),
      original.constraints
  )
}
Run Code Online (Sandbox Code Playgroud)

  • 对于 androidx 变体:`private val 原始:androidx.test.espresso.action.ScrollToAction = androidx.test.espresso.action.ScrollToAction()` (4认同)
  • 这对我有用。我还包括一个`scrollTo()`方法。`fun scrollTo():ViewAction = actionWithAssertions(ScrollToAction())` (3认同)

MR *_*ido 11

我有这个问题与CoordinatorLayout-> ViewPager-> NestedScrollView一个简单的工作从我得到相同的scrollTo()行为只是在屏幕上向上滑动:

onView(withId(android.R.id.content)).perform(ViewActions.swipeUp());
Run Code Online (Sandbox Code Playgroud)

  • 如果屏幕底部有一个按钮,则此解决方案将不起作用 =/ (3认同)

Lea*_*ira 5

米多先生的解决方案在某些情况下可能会奏效,但并非总是如此。如果屏幕底部有一些视图,则 RecyclerView 的滚动不会发生,因为单击将在 RecyclerView 之外开始。

解决此问题的一种方法是编写自定义 SwipeAction。像这样:

1 - 创建 CenterSwipeAction

public class CenterSwipeAction implements ViewAction {

    private final Swiper swiper;
    private final CoordinatesProvider startCoordProvide;
    private final CoordinatesProvider endCoordProvide;
    private final PrecisionDescriber precDesc;

    public CenterSwipeAction(Swiper swiper, CoordinatesProvider startCoordProvide,
                             CoordinatesProvider endCoordProvide, PrecisionDescriber precDesc) {
        this.swiper = swiper;
        this.startCoordProvide = startCoordProvide;
        this.endCoordProvide = endCoordProvide;
        this.precDesc = precDesc;
    }

    @Override public Matcher<View> getConstraints() {
        return withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE);
    }

    @Override public String getDescription() {
        return "swipe from middle of screen";
    }

    @Override
    public void perform(UiController uiController, View view) {
        float[] startCoord = startCoordProvide.calculateCoordinates(view);
        float[] finalCoord = endCoordProvide.calculateCoordinates(view);
        float[] precision =  precDesc.describePrecision();

        // you could try this for several times until Swiper.Status is achieved or try count is reached
        try {
            swiper.sendSwipe(uiController, startCoord, finalCoord, precision);
        } catch (RuntimeException re) {
            throw new PerformException.Builder()
                    .withActionDescription(this.getDescription())
                    .withViewDescription(HumanReadables.describe(view))
                    .withCause(re)
                    .build();
        }

        // ensures that the swipe has been run.
        uiController.loopMainThreadForAtLeast(ViewConfiguration.getPressedStateDuration());
    }
}
Run Code Online (Sandbox Code Playgroud)

2 - 创建返回 ViewAction 的方法

    private static ViewAction swipeFromCenterToTop() {
        return new CenterSwipeAction(Swipe.FAST,
                GeneralLocation.CENTER,
                view -> {
                    float[] coordinates =  GeneralLocation.CENTER.calculateCoordinates(view);
                    coordinates[1] = 0;
                    return coordinates;
                },
                Press.FINGER);
    }
Run Code Online (Sandbox Code Playgroud)

3 - 然后用它来滚动屏幕:

onView(withId(android.R.id.content)).perform(swipeFromCenterToTop());
Run Code Online (Sandbox Code Playgroud)

就是这样!通过这种方式,您可以控制滚动在屏幕中的发生方式。


Roc*_*nat 5

Barista 的scrollTo(R.id.button)作品涉及各种可滚动视图,也涉及NestedScrollView.

使用 Espresso 解决此类问题很有用。我们开发和使用它只是为了以快速可靠的方式编写 Espresso 测试。这是一个链接: https: //github.com/SchibstedSpain/Barista