Atul O Holic
Atul O Holic

Reputation: 6792

ImageView - Zoom on Stretch or Pull Down

How to achieve this feature, PullToZoom only with an ImageView (Without the ListView in the sample)?

Similar question, but no answer :(

Upvotes: 4

Views: 2368

Answers (2)

Mimmo Grottoli
Mimmo Grottoli

Reputation: 5773

What about using the Gesture Detector? You can find and implementation of what (I think) you need in the following code:

public class MainActivity extends AppCompatActivity {

    private static final String DEBUG_TAG = "Gestures";

    private GestureDetectorCompat mDetector;
    private ImageView imageView;
    private MyGestureListener myGestureListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = (ImageView) findViewById(R.id.image);

        myGestureListener = new MyGestureListener();
        mDetector = new GestureDetectorCompat(this, myGestureListener);
        imageView.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                int action = MotionEventCompat.getActionMasked(event);
                if (action == MotionEvent.ACTION_UP) {
                    myGestureListener.upDetected();
                }
                return mDetector.onTouchEvent(event);
            }
        });

        imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.test));

    }

    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

        private static final float MAX_ZOOM = 0.5f;

        private static final float PCT = 300f;
        private float delta;

        private ValueAnimator valueAnimator;

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

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (valueAnimator != null) {
                valueAnimator.cancel();
            }

            delta += distanceY;
            float pct = getPct(delta);
            imageView.setScaleX(1.0f + pct);
            imageView.setScaleY(1.0f + pct);
            return false;
        }

        void upDetected() {

            float pct = getPct(delta);

            valueAnimator = new ValueAnimator();
            valueAnimator.setFloatValues(pct, 0.0f);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    imageView.setScaleX(1.0f + (float) animation.getAnimatedValue());
                    imageView.setScaleY(1.0f + (float) animation.getAnimatedValue());
                }
            });
            valueAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    delta = 0f;
                    imageView.setScaleX(1.0f);
                    imageView.setScaleY(1.0f);
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
            valueAnimator.start();
        }

        private float getPct(float delta) {
            float pct = delta / PCT;
            if (pct >= MAX_ZOOM) {
                pct = MAX_ZOOM;
            }
            else if (pct <= -MAX_ZOOM) {
                pct = -MAX_ZOOM;
            }
            return pct;
        }
    }
}

The MainActivity has a simple ImageView. When you 'scroll' inside it, the gesture is detected and the image is scaled (up or down). When you remove the finger from the screen, the image is scaled back to its original size with a simple animation. If you want to avoid the zoom out, you just need to work on getPct() method.

EDIT

For example the getPtc could be something like this (if you are interested just to the zoom in)

private float getPct(float delta) {
    float pct = -delta / PCT;
    if (pct >= MAX_ZOOM) {
        pct = MAX_ZOOM;
    }
    else if (pct <= 0) {
        pct = 0;
    }
    return pct;
}

EDIT #2

It seems that the very first scroll event of the gesture detector is wide. I've added some code to ignore it

    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

    private static final float MAX_ZOOM = 0.8f;

    private static final float PCT = 300f;
    private float delta;

    private ValueAnimator valueAnimator;
    private boolean mFirstEvent = true;

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

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        if (valueAnimator != null) {
            valueAnimator.cancel();
        }

        if (mFirstEvent) {
            mFirstEvent = false;
            return false;
        }

        delta += distanceY;
        float pct = getPct(delta);
        imageView.setScaleX(1.0f + pct);
        imageView.setScaleY(1.0f + pct);
        textView.setScaleY(1.0f - pct);
        return false;
    }

    void upDetected() {

        mFirstEvent = true;
        float pct = getPct(delta);

        valueAnimator = new ValueAnimator();
        valueAnimator.setFloatValues(pct, 0.0f);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                imageView.setScaleX(1.0f + (Float) animation.getAnimatedValue());
                imageView.setScaleY(1.0f + (Float) animation.getAnimatedValue());
                textView.setScaleY(1.0f - (Float) animation.getAnimatedValue());
            }
        });
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                delta = 0f;
                imageView.setScaleX(1.0f);
                imageView.setScaleY(1.0f);
                textView.setScaleY(1.0f);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        valueAnimator.start();
    }

    private float getPct(float delta) {
        float pct = -delta / PCT;
        if (pct >= MAX_ZOOM) {
            pct = MAX_ZOOM;
        }
        else if (pct <= 0) {
            pct = 0;
        }
        return pct;
    }

    /*private float getPct(float delta) {
        float pct = delta / PCT;
        if (pct >= MAX_ZOOM) {
            pct = MAX_ZOOM;
        }
        else if (pct <= -MAX_ZOOM) {
            pct = -MAX_ZOOM;
        }
        return pct;
    }*/
}

Upvotes: 3

frgnvola
frgnvola

Reputation: 518

The Tinder app on android accomplishes a similar feature by overriding the onTouchEvent() method. Check out this post to see more.

Upvotes: 0

Related Questions