Click on EditText's drawable right with Espresso

前端 未结 4 634
小鲜肉
小鲜肉 2021-02-10 00:54

How could be possible to click on EditText\'s right drawable (check the screenshot)? I have tried several ways but I always get stuck.

public static Matcher

        
4条回答
  •  情话喂你
    2021-02-10 01:38

    Had to develop this custom action and matcher to test our discard drawables on the right of some text fields, this will click any drawable (left, top, right, bottom) of a TextView in an Espresso test.

    Usage:

    onView(withId(id)).perform(clickDrawables());
    

    Method:

    public static ViewAction clickDrawables()
    {
        return new ViewAction()
        {
            @Override
            public Matcher getConstraints()//must be a textview with drawables to do perform
            {
                return allOf(isAssignableFrom(TextView.class), new BoundedMatcher(TextView.class)
                {
                    @Override
                    protected boolean matchesSafely(final TextView tv)
                    {
                        if(tv.requestFocusFromTouch())//get fpocus so drawables become visible
                            for(Drawable d : tv.getCompoundDrawables())//if the textview has drawables then return a match
                                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())//get focus so drawables are visible
                {
                    Drawable[] drawables = tv.getCompoundDrawables();
    
                    Rect tvLocation = new Rect();
                    tv.getHitRect(tvLocation);
    
                    Point[] tvBounds = new Point[4];//find textview bound locations
                    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);//get drawable click location for left, top, right, bottom
                            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));
                        }
                }
            }
        };
    }
    



    This is a refinement I made to select a specific drawable to click:

    Usage:

    onView(withId(id)).perform(new ClickDrawableAction(ClickDrawableAction.Right));
    

    Method:

    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 getConstraints()
        {
            return allOf(isAssignableFrom(TextView.class), new BoundedMatcher(TextView.class)
            {
                @Override
                protected boolean matchesSafely(final TextView tv)
                {
                    //get focus so drawables are visible and if the textview has a drawable in the position then return a match
                    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;//we matched
            if(tv != null && tv.requestFocusFromTouch())//get focus so drawables are visible
            {
                //get the bounds of the drawable image
                Rect drawableBounds = tv.getCompoundDrawables()[drawableLocation].getBounds();
    
                //calculate the drawable click location for left, top, right, bottom
                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{}
    }
    

提交回复
热议问题