fweigl
fweigl

Reputation: 22028

Create fake drag event to move ViewPager around

I have a ViewPager with Fragments in it. I want to programmatically create a motion event to 'peek' at the Fragments left and right to the current Fragment in the ViewPager (showing part of the adjacent Fragments, then moving back to the current Fragment). It should look like a user was doing this.

I tried ViewPager.fakeDragBy but this happens instantly and is too fast. I had a look at MotionEvent.obtain() and View.dispatchTouchEvent, this seems the way to go to do this, right?

On which View do i have to dispatch the MotionEvents on? And do I have to manually dispatch several MotionEvents to achieve what I want, e.g. ACTION_DOWN, ACTION_???, ACTION_UP?

EDIT:

I tried the following:

public void drag(View view, float fromX, float toX, float fromY,
                 float toY, int stepCount) {

    long downTime = SystemClock.uptimeMillis();
    long eventTime = SystemClock.uptimeMillis();

    float y = fromY;
    float x = fromX;

    float yStep = (toY - fromY) / stepCount;
    float xStep = (toX - fromX) / stepCount;

    MotionEvent event = MotionEvent.obtain(downTime, eventTime,
            MotionEvent.ACTION_DOWN, x, y, 0);

    view.dispatchTouchEvent(event);

    for (int i = 0; i < stepCount; ++i) {

        y += yStep;
        x += xStep;
        eventTime = SystemClock.uptimeMillis();
        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
        view.dispatchTouchEvent(event);

    }

    eventTime = SystemClock.uptimeMillis();
    event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
    view.dispatchTouchEvent(event);

}

Which creates a drag motion just fine, problem is: it is very fast. I tried Thread.sleep() inside the loop and playing around with the eventTime (adding some time to it on every iteration within the for-loop), to no avail: the touch events are dispatched delayed, but the actual reaction of the ViewPager still happens very fast.

Upvotes: 4

Views: 9135

Answers (2)

Ercan
Ercan

Reputation: 3705

1st way:

Use OverScroller object with LinearInterpolator and set a duration duration (from x1 to x2 in 300ms maybe)

call computeScrollOffset() inside your for loop to find current position and break the loop when isFinished() returns true.


2nd way

Use Object animator with custom property and use your fakeDrag method in it and run it like a common animation.

Upvotes: 1

Sagar Pilkhwal
Sagar Pilkhwal

Reputation: 3993

You can do:

if (!viewpager.isFakeDragging()) {
    viewpager.beginFakeDrag();
}
viewpager.fakeDragBy(value);

Documentation: fakeDragBy(float), beginFakeDrag(), endFakeDrag().

and in onAnimationEnd()

@Override
public void onAnimationEnd(Animator mAnimation) {
    viewpager.endFakeDrag();
}

Upvotes: 1

Related Questions