OneCricketeer
OneCricketeer

Reputation: 191738

Implement feature like iOS app closing vertical Swipe-to-Dismiss with ViewPager

I currently have Views lined up horizontally in a ViewPager and can cycle through them with a PagerAdapter. Currently, to perform the action that I would like to do on swipe, I have to do a double-tap on the View's page. I could post code, but it's somewhat difficult to extract the necessary pieces...

What I would like is the ability to swipe vertically on these views, have them translate vertically with swipe and fade-out, and then perform an action when they reach a certain distance away from the edge of the device.

To get an idea of what I am thinking, in the Gallery app you can pinch an opened photo to zoom-out and open a horizontal filmstrip view. From there you can swipe up (or down) on a photo/video to delete it. For those who do not have the same Gallery app, it's exactly like closing applications on iOS.

I've tried scanning though the source code for the Gallery app, but no luck finding the correct Activity.

Upvotes: 8

Views: 3545

Answers (3)

OneCricketeer
OneCricketeer

Reputation: 191738

I ended up getting this working more-or-less by cloning the well-written Android-SwipeToDismiss library and just replacing the ListView code with a ViewPager.

The finished product looked like this.

end result

Upvotes: 4

bhavesh N
bhavesh N

Reputation: 787

Check the below code, this may helpful to you:

    public class MainActivity extends Activity implements View.OnTouchListener{

    private RelativeLayout baseLayout;

    private int previousFingerPosition = 0;
    private int baseLayoutPosition = 0;
    private int defaultViewHeight;

    private boolean isClosing = false;
    private boolean isScrollingUp = false;
    private boolean isScrollingDown = false;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_popup);
        baseLayout = (RelativeLayout) findViewById(R.id.base_popup_layout);//this is the main layout
        baseLayout.setOnTouchListener(this);
    }


    public boolean onTouch(View view, MotionEvent event) {

        // Get finger position on screen
        final int Y = (int) event.getRawY();

        // Switch on motion event type
        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                // save default base layout height
                defaultViewHeight = baseLayout.getHeight();

                // Init finger and view position
                previousFingerPosition = Y;
                baseLayoutPosition = (int) baseLayout.getY();
                break;

            case MotionEvent.ACTION_UP:
                // If user was doing a scroll up
                if(isScrollingUp){
                    // Reset baselayout position
                    baseLayout.setY(0);
                    // We are not in scrolling up mode anymore
                    isScrollingUp = false;
                }

                // If user was doing a scroll down
                if(isScrollingDown){
                    // Reset baselayout position
                    baseLayout.setY(0);
                    // Reset base layout size
                    baseLayout.getLayoutParams().height = defaultViewHeight;
                    baseLayout.requestLayout();
                    // We are not in scrolling down mode anymore
                    isScrollingDown = false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(!isClosing){
                    int currentYPosition = (int) baseLayout.getY();

                    // If we scroll up
                    if(previousFingerPosition >Y){
                        // First time android rise an event for "up" move
                        if(!isScrollingUp){
                            isScrollingUp = true;
                        }

                    // Has user scroll down before -> view is smaller than it's default size -> resize it instead of change it position
                    if(baseLayout.getHeight()<defaultViewHeight){
                        baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
                        baseLayout.requestLayout();
                    }
                    else {
                        // Has user scroll enough to "auto close" popup ?
                        if ((baseLayoutPosition - currentYPosition) > defaultViewHeight / 4) {
                            closeUpAndDismissDialog(currentYPosition);
                            return true;
                        }

                        //
                    }
                    baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));

                }
                // If we scroll down
                else{

                    // First time android rise an event for "down" move
                    if(!isScrollingDown){
                        isScrollingDown = true;
                    }

                    // Has user scroll enough to "auto close" popup ?
                    if (Math.abs(baseLayoutPosition - currentYPosition) > defaultViewHeight / 2)
                    {
                        closeDownAndDismissDialog(currentYPosition);
                        return true;
                    }

                    // Change base layout size and position (must change position because view anchor is top left corner)
                    baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
                    baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
                    baseLayout.requestLayout();
                }

                // Update position
                previousFingerPosition = Y;
            }
            break;
        }
        return true;
    }
}

For animation use the below methods:

   public void closeUpAndDismissDialog(int currentPosition){
    isClosing = true;
    ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, -baseLayout.getHeight());
    positionAnimator.setDuration(300);
    positionAnimator.addListener(new Animator.AnimatorListener()
    {
        . . .
        @Override
        public void onAnimationEnd(Animator animator)
        {
            finish();
        }
        . . .
    });
    positionAnimator.start();
}

public void closeDownAndDismissDialog(int currentPosition){
    isClosing = true;
    Display display = getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    int screenHeight = size.y;
    ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, screenHeight+baseLayout.getHeight());
    positionAnimator.setDuration(300);
    positionAnimator.addListener(new Animator.AnimatorListener()
     {
        . . .
        @Override
        public void onAnimationEnd(Animator animator)
        {
            finish();
        }
        . . .
    });
    positionAnimator.start();
}

Upvotes: 1

geokavel
geokavel

Reputation: 619

view.setOnTouchListener(new View.OnTouchListener(){
    public boolean onTouch(View v, MotionEvent motion) {
       float y = motion.getY();
       /* NOTE: the following line might need to be in runOnUiThread() */
       view.animate().alpha(1-Math.abs(y-height/2)/(height/2)).setDuration(50).start();
       return true; //false if you want to pass this event on to other listeners
    }
});

The explanation for using 1-Math.abs(y-height/2)/(height/2) is that I want alpha to be 1 when I am in the center, and alpha to be 0 when it is at the top or bottom. You have to determine yourself how you obtain the height value, or if you want to use a different method to calculate alpha. If you want to get the touch position relative to the screen instead of the position relative to the view, use getRawY().

Additionally, it may be useful for you to know that to see if the MotionEvent is a press, drag, or release event, use motion.getAction() == with MotionEvent.ACTION_UP, MotionEvent.ACTION_MOVE, and MotionEvent.ACTION_DOWN, respectively.

Upvotes: 4

Related Questions