Wait for view pager animations with espresso?

2020-02-08 08:29发布

Trying to do some tests with a ViewPager.

I want to swipe between tabs, and I don't want to continue until the swipe is complete. But there doesn't appear to be a way to turn off the animation for the view pager (all animations under the developer options are disabled).

So this always results in a test failure, because the view pager hasn't completed it's animation, and so the view is not completely displayed yet:

// swipe left
onView(withId(R.id.viewpager)).check(matches(isDisplayed())).perform(swipeLeft());

// check to ensure that the next tab is completely visible.
onView(withId(R.id.next_tab)).check(matches(isCompletelyDisplayed()));

Is there an elegant or maybe even recommended way to do this, or am I stuck putting some kind of timed wait in there?

4条回答
贪生不怕死
2楼-- · 2020-02-08 08:51

You can either do a lot of work and use an IdlingResource to implement an OnPageChangeListener

or simply:

SystemClock.sleep(500);
查看更多
Explosion°爆炸
3楼-- · 2020-02-08 08:59

The IdlingResource @Simas suggests is actually pretty simple to implement:

public class ViewPagerIdlingResource implements IdlingResource {

    private final String mName;

    private boolean mIdle = true; // Default to idle since we can't query the scroll state.

    private ResourceCallback mResourceCallback;

    public ViewPagerIdlingResource(ViewPager viewPager, String name) {
        viewPager.addOnPageChangeListener(new ViewPagerListener());
        mName = name;
    }

    @Override
    public String getName() {
        return mName;
    }

    @Override
    public boolean isIdleNow() {
        return mIdle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        mResourceCallback = resourceCallback;
    }

    private class ViewPagerListener extends ViewPager.SimpleOnPageChangeListener {

        @Override
        public void onPageScrollStateChanged(int state) {
            mIdle = (state == ViewPager.SCROLL_STATE_IDLE
                    // Treat dragging as idle, or Espresso will block itself when swiping.
                    || state == ViewPager.SCROLL_STATE_DRAGGING);
            if (mIdle && mResourceCallback != null) {
                mResourceCallback.onTransitionToIdle();
            }
        }
    }
}
查看更多
Summer. ? 凉城
4楼-- · 2020-02-08 09:03

Try this,

    onView(withId(R.id.pager)).perform(pagerSwipeRight()).perform(pagerSwipeLeft());

    private GeneralSwipeAction pagerSwipeRight(){
        return new GeneralSwipeAction(Swipe.SLOW, GeneralLocation.CENTER_LEFT,
                GeneralLocation.CENTER_RIGHT, Press.FINGER);
    }

    private GeneralSwipeAction pagerSwipeLeft(){
        return new GeneralSwipeAction(Swipe.SLOW, GeneralLocation.CENTER_RIGHT,
                GeneralLocation.CENTER_LEFT, Press.FINGER);
    }
查看更多
混吃等死
5楼-- · 2020-02-08 09:11

I was having issues with @vaughandroid approach, so I did some changes to his approach. This approach will set idle to false as soon as it detects a scrolling is happening and "force" the ViewPager to finish scrolling by using setCurrentItem().

public class ViewPagerIdlingResource implements IdlingResource {
    private volatile boolean mIdle = true; // Default to idle since we can't query the scroll state.

    private ResourceCallback mResourceCallback;

    private ViewPager mViewPager;

    public static ViewPagerIdlingResource waitViewPagerSwipe(ViewPager viewPager) {
        return new ViewPagerIdlingResource(viewPager);
    }

    private ViewPagerIdlingResource(ViewPager viewPager) {
        mViewPager = viewPager;
        mViewPager.addOnPageChangeListener(new ViewPagerListener());
    }

    @Override
    public String getName() {
        return ViewPagerIdlingResource.class.getSimpleName();
    }

    @Override
    public boolean isIdleNow() {
        return mIdle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        mResourceCallback = resourceCallback;
    }

    private class ViewPagerListener extends ViewPager.SimpleOnPageChangeListener {
        float mPositionOffset = 0.0f;

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (isSwipingToRight(positionOffset)) {
                mIdle = false;
                mViewPager.setCurrentItem(position + 1);
            } else if (isSwipingToLeft(positionOffset)) {
                mIdle = false;
                mViewPager.setCurrentItem(position - 1);
            }

            mPositionOffset = positionOffset;

            if (positionOffset == 0 && !mIdle && mResourceCallback != null) {
                mResourceCallback.onTransitionToIdle();
                mIdle = true;
                mPositionOffset = 0.0f;
            }
        }

        private boolean isSwipingToRight(float positionOffset) {
            return mPositionOffset != 0.0f && positionOffset > mPositionOffset && mIdle;
        }

        private boolean isSwipingToLeft(float positionOffset) {
            return mPositionOffset != 0.0f && positionOffset < mPositionOffset && mIdle;
        }
    }
}
查看更多
登录 后发表回答