Выбор детского просмотра по индексу с помощью Espresso
С помощью Espresso при использовании пользовательского вида виджетов с дочерними изображениями, который тип Matcher можно использовать для выбора n-го дочернего элемента?
Пример:
+--------->NumberSlider{id=2131296844, res-name=number_slider, visibility=VISIBLE, width=700, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=10.0, y=0.0, child-count=7}
|
+---------->NumberView{id=-1, visibility=VISIBLE, width=99, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=99.0, y=0.0}
|
+---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=199.0, y=0.0}
|
+---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=299.0, y=0.0}
|
+---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=399.0, y=0.0}
|
+---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=499.0, y=0.0}
|
+---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=599.0, y=0.0}
Ответы
Ответ 1
public static Matcher<View> nthChildOf(final Matcher<View> parentMatcher, final int childPosition) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("with "+childPosition+" child view of type parentMatcher");
}
@Override
public boolean matchesSafely(View view) {
if (!(view.getParent() instanceof ViewGroup)) {
return parentMatcher.matches(view.getParent());
}
ViewGroup group = (ViewGroup) view.getParent();
return parentMatcher.matches(view.getParent()) && group.getChildAt(childPosition).equals(view);
}
};
}
Чтобы использовать его
onView(nthChildOf(withId(R.id.parent_container), 0).check(matches(withText("I am the first child"));
Ответ 2
Чтобы немного улучшить решение Maragues, я внес несколько изменений.
Решение состоит в создании пользовательского Matcher <View> который обертывает другой Matcher <View> для родительского представления и присваивает индекс дочернего представления для соответствия.
public static Matcher<View> nthChildOf(final Matcher<View> parentMatcher, final int childPosition) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("position " + childPosition + " of parent ");
parentMatcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
if (!(view.getParent() instanceof ViewGroup)) return false;
ViewGroup parent = (ViewGroup) view.getParent();
return parentMatcher.matches(parent)
&& parent.getChildCount() > childPosition
&& parent.getChildAt(childPosition).equals(view);
}
};
}
Подробное объяснение
Вы можете переопределить метод describeTo, чтобы дать понятное описание макета, добавив к аргументу Description. Вы также захотите распространить вызов describeTo на родительский матчи, чтобы оно также добавилось.
@Override
public void describeTo(Description description) {
description.appendText("position " + childPosition + " of parent "); // Add this matcher description.
parentMatcher.describeTo(description); // Add the parentMatcher description.
}
Затем вы должны переопределить matchSafely, который определит, когда совпадение в иерархии представлений найдено. Когда вызывается с представлением, чей родительский элемент соответствует предоставленному родительскому совпадению, проверьте, что представление равно ребенку в предоставленной позиции.
Если родительский элемент не имеет дочернего элемента, большего, чем дочерняя, getChildAt возвращает null и вызывает сбой теста. Лучше избегать сбоев и разрешить тест сбой, чтобы мы получили правильный отчет об испытаниях и сообщение об ошибке.
@Override
public boolean matchesSafely(View view) {
if (!(view.getParent() instanceof ViewGroup)) return false; // If it not a ViewGroup we know it doesn't match.
ViewGroup parent = (ViewGroup) view.getParent();
return parentMatcher.matches(parent) // Check that the parent matches.
&& parent.getChildCount() > childPosition // Make sure there enough children.
&& parent.getChildAt(childPosition).equals(view); // Check that this is the right child.
}
Ответ 3
Если вы можете получить родительское представление. Может быть эта ссылка, которая определила совпадение для получения первого дочернего элемента представления, может дать вам некоторую подсказку.
public static Matcher<View> firstChildOf(final Matcher<View> parentMatcher) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("with first child view of type parentMatcher");
}
@Override
public boolean matchesSafely(View view) {
if (!(view.getParent() instanceof ViewGroup)) {
return parentMatcher.matches(view.getParent());
}
ViewGroup group = (ViewGroup) view.getParent();
return parentMatcher.matches(view.getParent()) && group.getChildAt(0).equals(view);
}
};
}