需要开发这个自定义操作和匹配器来测试我们在某些文本字段右侧的丢弃可绘制对象,
这将在Espresso测试中单击TextView的任何可绘制对象(左,上,右,下)。
用法:
onView(withId(id)).perform(clickDrawables())
方法:
public static ViewAction clickDrawables()
{
return new ViewAction()
{
@Override
public Matcher<View> getConstraints()
{
return allOf(isAssignableFrom(TextView.class), new BoundedMatcher<View, TextView>(TextView.class)
{
@Override
protected boolean matchesSafely(final TextView tv)
{
if(tv.requestFocusFromTouch())
for(Drawable d : tv.getCompoundDrawables())
if(d != null)
return true;
return false;
}
@Override
public void describeTo(Description description)
{
description.appendText("has drawable");
}
});
}
@Override
public String getDescription()
{
return "click drawables";
}
@Override
public void perform(final UiController uiController, final View view)
{
TextView tv = (TextView)view;
if(tv != null && tv.requestFocusFromTouch())
{
Drawable[] drawables = tv.getCompoundDrawables();
Rect tvLocation = new Rect();
tv.getHitRect(tvLocation);
Point[] tvBounds = new Point[4];
tvBounds[0] = new Point(tvLocation.left, tvLocation.centerY());
tvBounds[1] = new Point(tvLocation.centerX(), tvLocation.top);
tvBounds[2] = new Point(tvLocation.right, tvLocation.centerY());
tvBounds[3] = new Point(tvLocation.centerX(), tvLocation.bottom);
for(int location = 0; location < 4; location++)
if(drawables[location] != null)
{
Rect bounds = drawables[location].getBounds();
tvBounds[location].offset(bounds.width() / 2, bounds.height() / 2);
if(tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, tvBounds[location].x, tvBounds[location].y, 0)))
tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, tvBounds[location].x, tvBounds[location].y, 0));
}
}
}
};
}
这是我对选择特定可绘制对象进行单击的改进:
用法:
onView(withId(id)).perform(new ClickDrawableAction(ClickDrawableAction.Right))
方法:
public static class ClickDrawableAction implements ViewAction
{
public static final int Left = 0;
public static final int Top = 1;
public static final int Right = 2;
public static final int Bottom = 3;
@Location
private final int drawableLocation;
public ClickDrawableAction(@Location int drawableLocation)
{
this.drawableLocation = drawableLocation;
}
@Override
public Matcher<View> getConstraints()
{
return allOf(isAssignableFrom(TextView.class), new BoundedMatcher<View, TextView>(TextView.class)
{
@Override
protected boolean matchesSafely(final TextView tv)
{
return tv.requestFocusFromTouch() && tv.getCompoundDrawables()[drawableLocation] != null;
}
@Override
public void describeTo(Description description)
{
description.appendText("has drawable");
}
});
}
@Override
public String getDescription()
{
return "click drawable ";
}
@Override
public void perform(final UiController uiController, final View view)
{
TextView tv = (TextView)view;
if(tv != null && tv.requestFocusFromTouch())
{
Rect drawableBounds = tv.getCompoundDrawables()[drawableLocation].getBounds();
final Point[] clickPoint = new Point[4];
clickPoint[Left] = new Point(tv.getLeft() + (drawableBounds.width() / 2), (int)(tv.getPivotY() + (drawableBounds.height() / 2)));
clickPoint[Top] = new Point((int)(tv.getPivotX() + (drawableBounds.width() / 2)), tv.getTop() + (drawableBounds.height() / 2));
clickPoint[Right] = new Point(tv.getRight() + (drawableBounds.width() / 2), (int)(tv.getPivotY() + (drawableBounds.height() / 2)));
clickPoint[Bottom] = new Point((int)(tv.getPivotX() + (drawableBounds.width() / 2)), tv.getBottom() + (drawableBounds.height() / 2));
if(tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, clickPoint[drawableLocation].x, clickPoint[drawableLocation].y, 0)))
tv.dispatchTouchEvent(MotionEvent.obtain(android.os.SystemClock.uptimeMillis(), android.os.SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, clickPoint[drawableLocation].x, clickPoint[drawableLocation].y, 0));
}
}
@IntDef({ Left, Top, Right, Bottom })
@Retention(RetentionPolicy.SOURCE)
public @interface Location{}
}