1

I am trying to create an animation:

Use Case : 1. User swipes/ drags item to right ( horizontally ), item gets added into basket. If he again swipes it adds one more of the same item into the basket. 2. User swipes/ drags item to left ( horizontally ), item gets removes from the basket, if was added before, if there is no item in the basket we leave it as it is.

Drag effect : When user drags, item gets moved along with the finger. As soon as he leave it, items gets back to its position.

Zoom effect : When user clicks on the item, item gets zoomed, letting user know that item has been added into the basket. ( replicated method of right dragged ).

I tried to use OnSwipeTouchListener Class specially for this purpose :

import android.content.Context;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

import PointF;

public class OnSwipeTouchListener implements OnTouchListener {

    private final GestureDetector gestureDetector;
    PointF DownPT = null;
    PointF StartPT = null;
    float startX;
    float startY;

    public OnSwipeTouchListener(Context context , float x, float y) {
        gestureDetector = new GestureDetector(context, new GestureListener());
        DownPT = new PointF();
        StartPT = new PointF();
        this.startX = x;
        this.startY = y;
    }

    public void onSwipeLeft() {
    }

    public void onSwipeRight() {
    }

    public boolean onTouch(View v, MotionEvent event) {

        int eid = event.getAction();

        switch (eid) {
            case MotionEvent.ACTION_MOVE:

                PointF mv = new PointF(event.getX() - DownPT.x, event.getY() - DownPT.y);

                v.setX((int) (StartPT.x + mv.x));
                v.setY(this.startY);
                StartPT = new PointF(v.getX(), v.getY());
                break;
            case MotionEvent.ACTION_DOWN:
                DownPT.x = event.getX();
                DownPT.y = event.getY();
                StartPT = new PointF(v.getX(), v.getY());

                break;
            case MotionEvent.ACTION_UP:
                // Move image back to its original position.
                v.setX(this.startX);
                v.setY(this.startY);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

                break;
            default:
                v.setX(this.startX);
                v.setY(this.startY);

                break;
        }

        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_DISTANCE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceX > 0)
                    onSwipeRight();
                else
                    onSwipeLeft();
                return true;
            }
            return false;
        }
    }
}

When My method OnTouch is like below, my onSwipeRight() and onSwipeLeft() gets triggered but when I have implemented onTouch as above in the code, these two methods does not get triggered.

public boolean onTouch(View v, MotionEvent event) {
  return gestureDetector.onTouchEvent(event);
}

Regarding Zoom effect on Click event.

In my Fragment I am zooming image like this.

offerimg1.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            zoomAnimation(v, offerimg1);
        }
    });

And my zoomAnimation method is :

private void zoomAnimation(View view,ImageView image) {
        Animation animation = AnimationUtils.loadAnimation(getActivity().getApplicationContext(), R.anim.zoom);
        image.startAnimation(animation);
    }

My Zoom is working unless I have not implemented in my fragmented :

 offerimg1.setOnTouchListener(new OnSwipeTouchListener(getActivity().getApplicationContext(),offerimg1.getX(),offerimg1.getY()) {
            @Override
            public void onSwipeLeft() {
                Log.d("onTouch "," swipe left");
            }

            @Override
            public void onSwipeRight() {
                Log.d("onTouch "," swipe right");
            }

        });

I am not sure what is the collision between these events. I need to achieve my above use case, every events should work on each image. As my images are in a scroll view in a fragment.

If you want I can share more code here. Please let me know if I could not clarify my problem.

I really appreciate your help.

Regards, Shashank Pratap

shank2111
  • 105
  • 1
  • 11
  • Is there anyone who can help. I tried to resolve this for several hours, but could not get success. If any can just point the mistake, without giving any code example. I will accept that answer. – shank2111 Jul 11 '15 at 18:17
  • Ok, I am able to resolve the problem of onClick event, using the suggestion by http://stackoverflow.com/questions/9965695/how-to-distinguish-between-move-and-click-in-ontouchevent/29933115#29933115 But I am still stuck with onSwipeLeft() and onSwipeRight().. After on Touch event is fired, it should propagate to these two methods. – shank2111 Jul 12 '15 at 10:30
  • Yes I found the problem with onSwipeLeft() and onSwipeRight().. since my image is moving along with my finger, this is the reason distanceX is turing out to be zero, which is always less than static SWIPE_DISTANCE_THRESHOLD. and in the code we are saying that if distanceX is negative its swipeLeft() else swipeRight(). Any Comments Please.. – shank2111 Jul 12 '15 at 12:03

1 Answers1

0

Finally I have solved the problem,

Found Problem with above code :

onSwipeLeft() and onSwipeRight().. since my image is moving along with my finger, this is the reason distanceX is turing out to be zero, which is always less than static SWIPE_DISTANCE_THRESHOLD. and in the code we are saying that if distanceX is negative its swipeLeft() else swipeRight()

Solution : We needed someway to trap which way user is moving his/her finger, therefore I decided within MotionEvent.ACTION_MOVE: event, find if mv.x is negative or mv.x is positive. Once I found it, it was easy to make decision, and on that basis we can decide which method to run within GestureListener.

Here is my OnSwipeTouchListener, I am still not sure if this is the best solution for this case, but I found it working on AVD as well as on Android device.

I am still open to find a nice and clear method ( best practice ) of doing this :

import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.Toast;

import R;

import StartingPoints;
import PointF;

public class OnSwipeTouchListener implements OnTouchListener {

    private static final String APP = OnSwipeTouchListener.class.getName() ;
    private final GestureDetector gestureDetector;
    PointF DownPT = null;
    PointF StartPT = null;

    Context _context;
    static  boolean isLeftMoved = false;
    static  boolean isRightMoved = false;

    /**
     * Max allowed duration for a "click", in milliseconds.
     */
    private static final int MAX_CLICK_DURATION = 1000;

    /**
     * Max allowed distance to move during a "click", in DP.
     */
    private static final int MAX_CLICK_DISTANCE = 15;
    private static final float PIXELS_PER_SECOND = 5;

    private long pressStartTime;
    private float pressedX;
    private float pressedY;
    private boolean stayedWithinClickDistance;
    Resources resources;
    private float startX = 0f;
    private float startY = 0f;
    private boolean isNewImage = true;




    public OnSwipeTouchListener(Context context, Resources resources) {
        this._context = context;
        gestureDetector = new GestureDetector(context, new GestureListener());
        DownPT = new PointF();
        StartPT = new PointF();
        this.resources = resources;

    }

    public void onSwipeLeft() {
    }

    public void onSwipeRight() {
    }

    public boolean onTouch(View v, MotionEvent e) {
        if(isNewImage){
            isNewImage = false;
            startX = v.getX();
            startY = v.getY();
        }
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //animation code
                DownPT.x = e.getX();
                DownPT.y = e.getY();
                StartPT = new PointF(v.getX(), v.getY());


                //calculation code
                pressStartTime = System.currentTimeMillis();
                pressedX = e.getX();
                pressedY = e.getY();
                stayedWithinClickDistance = true;
                break;

            case MotionEvent.ACTION_MOVE:
                // animation code
                PointF mv = new PointF(e.getX() - DownPT.x, e.getY() - DownPT.y);
                v.setX((int) (StartPT.x + mv.x));
                v.setY(startY);

                StartPT = new PointF(v.getX(), v.getY());
                if(mv.x < 0 ){
                    isLeftMoved = true;
                }
                if(mv.x > 0 ){
                    isRightMoved = true;
                }

                //calculation code
                if (stayedWithinClickDistance && distance(pressedX, pressedY, e.getX(), e.getY()) > MAX_CLICK_DISTANCE) {
                    stayedWithinClickDistance = false;
                }

                Log.d("Moved ","Item moved");
                break;
            case MotionEvent.ACTION_UP:
                if(!stayedWithinClickDistance){
                    v.setX(startX);
                    v.setY(startY);
                    isNewImage = true;
                }


                long pressDuration = System.currentTimeMillis() - pressStartTime;
                if (pressDuration < MAX_CLICK_DURATION && stayedWithinClickDistance) {
                    // Click event has occurred
                    Log.d("Stayed"," With Click event");
                    zoomAnimation(v);
                    isNewImage = true;
                }


                break;
            default:
                // Move image back to its original position, by default
                Log.d("default", "This is default ");
                v.setX(startX);
                v.setY(startY);
                isNewImage = true;
                break;

        }

        return gestureDetector.onTouchEvent(e);
    }


    private  float distance(float x1, float y1, float x2, float y2) {
        float dx = x1 - x2;
        float dy = y1 - y2;
        float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
        return pxToDp(distanceInPx);
    }

    private  float pxToDp(float px) {
        return px / resources.getDisplayMetrics().density;
    }

    private void zoomAnimation(View view) {
        Animation animation = AnimationUtils.loadAnimation(_context, R.anim.zoom);
        view.startAnimation(animation);
    }





    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_DISTANCE_THRESHOLD = 20;
        private static final int SWIPE_VELOCITY_THRESHOLD = 50;



        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            float maxFlingVelocity    = ViewConfiguration.get(_context).getScaledMaximumFlingVelocity();
            float velocityPercentX    = velocityX / maxFlingVelocity;          // the percent is a value in the range of (0, 1]
            float normalizedVelocityX = velocityPercentX * PIXELS_PER_SECOND;  // where PIXELS_PER_SECOND is a device-independent measurement

            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();

            if (isLeftMoved || isRightMoved) {
                if(isRightMoved) {
                    isLeftMoved = false;
                    isRightMoved = false;
                    onSwipeRight();
                }
                else {
                    isLeftMoved = false;
                    isRightMoved = false;
                    onSwipeLeft();
                }
            }

            return false;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            return true;
        }
    }
}

Best regards, Shashank Pratap

shank2111
  • 105
  • 1
  • 11