使用Espresso单击RecyclerView项目内的视图

Fil*_*mos 92 android android-espresso android-recyclerview

如何使用Espresso单击RecyclerView项目中的特定视图?我知道我可以点击位置0处的项目:

onView(withId(R.id.recyclerView)) .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));

但是我需要点击该项目内的特定视图而不是项目本身.

提前致谢.

- 编辑 -

更确切地说:我有一个RecyclerView(R.id.recycler_view)项目是CardView(R.id.card_view).在每个CardView内部,我有四个按钮(除其他外),我想点击一个特定的按钮(R.id.bt_deliver).

我想使用Espresso 2.0的新功能,但我不确定是否可行.

如果不可能,我想使用这样的东西(使用托马斯凯勒代码):

onRecyclerItemView(R.id.card_view, ???, withId(R.id.bt_deliver)).perform(click());
Run Code Online (Sandbox Code Playgroud)

但我不知道该在问号上放些什么.

bla*_*ade 124

您可以使用自定义视图操作执行此操作.

public class MyViewAction {

    public static ViewAction clickChildViewWithId(final int id) {
        return new ViewAction() {
            @Override
            public Matcher<View> getConstraints() {
                return null;
            }

            @Override
            public String getDescription() {
                return "Click on a child view with specified id.";
            }

            @Override
            public void perform(UiController uiController, View view) {
                View v = view.findViewById(id);
                v.performClick();
            }
        };
    }

}
Run Code Online (Sandbox Code Playgroud)

然后你可以点击它

onView(withId(R.id.rv_conference_list)).perform(
            RecyclerViewActions.actionOnItemAtPosition(0, MyViewAction.clickChildViewWithId(R.id. bt_deliver)));
Run Code Online (Sandbox Code Playgroud)

  • 适用于浓缩咖啡:espresso-contrib:2.2.2但不是2.2.1任何原因?我有一些依赖,因为我不能使用2.2.2. (3认同)
  • 我最初得到的是NullPointerException,所以我必须实现getConstraints()来避免这种情况.以下对我有用:public Matcher <View> getConstraints(){return isAssignableFrom(View.class); } (3认同)
  • 我会删除null检查,这样如果没有找到子视图,则抛出异常而不是静默地执行任何操作. (2认同)

And*_*rey 61

现在使用android.support.test.espresso.contrib它变得更容易:

1)添加测试依赖项

androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.0') {
    exclude group: 'com.android.support', module: 'appcompat'
    exclude group: 'com.android.support', module: 'support-v4'
    exclude module: 'recyclerview-v7'
}
Run Code Online (Sandbox Code Playgroud)

*排除3个模块,因为很可能你已经拥有它

2)然后做类似的事情

onView(withId(R.id.recycler_grid))
            .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
Run Code Online (Sandbox Code Playgroud)

要么

onView(withId(R.id.recyclerView))
  .perform(RecyclerViewActions.actionOnItem(
            hasDescendant(withText("whatever")), click()));
Run Code Online (Sandbox Code Playgroud)

要么

onView(withId(R.id.recycler_linear))
            .check(matches(hasDescendant(withText("whatever"))));
Run Code Online (Sandbox Code Playgroud)

  • 如何点击让我们说在列表的第5项中的具体视图?在提供的示例中,我只看到如何点击第5项或点击和带有后代视图的项目,但不是两者都在一起,或者我是否错过了什么? (8认同)
  • 当您想单击 RecyclerView 内的复选框时,它是没有用的。 (2认同)
  • 在kotlin中,actionOnItemAtPosition需要类型参数。不知道该放在哪里。 (2认同)

Ser*_*gey 6

尝试下一步方法:

    onView(withRecyclerView(R.id.recyclerView)
                    .atPositionOnView(position, R.id.bt_deliver))
                    .perform(click());

    public static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) {
            return new RecyclerViewMatcher(recyclerViewId);
    }

public class RecyclerViewMatcher {
    final int mRecyclerViewId;

    public RecyclerViewMatcher(int recyclerViewId) {
        this.mRecyclerViewId = recyclerViewId;
    }

    public Matcher<View> atPosition(final int position) {
        return atPositionOnView(position, -1);
    }

    public Matcher<View> atPositionOnView(final int position, final int targetViewId) {

        return new TypeSafeMatcher<View>() {
            Resources resources = null;
            View childView;

            public void describeTo(Description description) {
                int id = targetViewId == -1 ? mRecyclerViewId : targetViewId;
                String idDescription = Integer.toString(id);
                if (this.resources != null) {
                    try {
                        idDescription = this.resources.getResourceName(id);
                    } catch (Resources.NotFoundException var4) {
                        idDescription = String.format("%s (resource name not found)", id);
                    }
                }

                description.appendText("with id: " + idDescription);
            }

            public boolean matchesSafely(View view) {

                this.resources = view.getResources();

                if (childView == null) {
                    RecyclerView recyclerView =
                            (RecyclerView) view.getRootView().findViewById(mRecyclerViewId);
                    if (recyclerView != null) {

                        childView = recyclerView.findViewHolderForAdapterPosition(position).itemView;
                    }
                    else {
                        return false;
                    }
                }

                if (targetViewId == -1) {
                    return view == childView;
                } else {
                    View targetView = childView.findViewById(targetViewId);
                    return view == targetView;
                }

            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

这是我如何解决Kotlin中的问题:

fun clickOnViewChild(viewId: Int) = object : ViewAction {
    override fun getConstraints() = null

    override fun getDescription() = "Click on a child view with specified id."

    override fun perform(uiController: UiController, view: View) = click().perform(uiController, view.findViewById<View>(viewId))
}
Run Code Online (Sandbox Code Playgroud)

然后

onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(position, clickOnViewChild(R.id.viewToClickInTheRow)))
Run Code Online (Sandbox Code Playgroud)

  • 我遇到 E/TestRunner: java.lang.NullPointerException: 尝试在空对象引用上调用虚拟方法 'void android.view.View.getLocationOnScreen(int[])' ;知道为什么吗? (2认同)

erl*_*man 5

您可以点击第三个项目recyclerView就像这样:

onView(withId(R.id.recyclerView)).perform(
                RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(2,click()))
Run Code Online (Sandbox Code Playgroud)

不要忘记提供ViewHolder类型,以便推理不会失败。