Développement android zoom imageview java

Développement android zoom imageview java

Bonjour, développement android zoom imageview java pour insérer l’effet d’un Zoom sur une image (<ImageViview>) sous android, moi j’utilise une classe java spécial que j’ai trouvé sur internet.Son utilisation est très simple .

Pour créer un effet zoom avec ma méthode il faut ajouter cette classe java à votre projet, nommez la TouchImageView  :

package com.maxou.projet;


import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.OverScroller;
import android.widget.Scroller;

public class TouchImageView extends ImageView {

    private static final String DEBUG = "DEBUG";

    private static final float SUPER_MIN_MULTIPLIER = .75f;
    private static final float SUPER_MAX_MULTIPLIER = 1.25f;

    private float normalizedScale;

    private Matrix matrix, prevMatrix;

    private static enum State { NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM };
    private State state;

    private float minScale;
    private float maxScale;
    private float superMinScale;
    private float superMaxScale;
    private float[] m;

    private Context context;
    private Fling fling;

    private ScaleType mScaleType;

    private boolean imageRenderedAtLeastOnce;
    private boolean onDrawReady;

    private ZoomVariables delayedZoomVariables;

    private int viewWidth, viewHeight, prevViewWidth, prevViewHeight;

    private float matchViewWidth, matchViewHeight, prevMatchViewWidth, prevMatchViewHeight;

    private ScaleGestureDetector mScaleDetector;
    private GestureDetector mGestureDetector;
    private GestureDetector.OnDoubleTapListener doubleTapListener = null;
    private OnTouchListener userTouchListener = null;
    private OnTouchImageViewListener touchImageViewListener = null;

    public TouchImageView(Context context) {
        super(context);
        sharedConstructing(context);
    }

    public TouchImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        sharedConstructing(context);
    }

    public TouchImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        sharedConstructing(context);
    }

    private void sharedConstructing(Context context) {
        super.setClickable(true);
        this.context = context;
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        mGestureDetector = new GestureDetector(context, new GestureListener());
        matrix = new Matrix();
        prevMatrix = new Matrix();
        m = new float[9];
        normalizedScale = 1;
        if (mScaleType == null) {
            mScaleType = ScaleType.FIT_CENTER;
        }
        minScale = 1;
        maxScale = 3;
        superMinScale = SUPER_MIN_MULTIPLIER * minScale;
        superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);
        setState(State.NONE);
        onDrawReady = false;
        super.setOnTouchListener(new PrivateOnTouchListener());
    }

    @Override
    public void setOnTouchListener(View.OnTouchListener l) {
        userTouchListener = l;
    }

    public void setOnTouchImageViewListener(OnTouchImageViewListener l) {
        touchImageViewListener = l;
    }

    public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener l) {
        doubleTapListener = l;
    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        savePreviousImageValues();
        fitImageToView();
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        savePreviousImageValues();
        fitImageToView();
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        savePreviousImageValues();
        fitImageToView();
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        savePreviousImageValues();
        fitImageToView();
    }

    @Override
    public void setScaleType(ScaleType type) {
        if (type == ScaleType.FIT_START || type == ScaleType.FIT_END) {
            throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
        }
        if (type == ScaleType.MATRIX) {
            super.setScaleType(ScaleType.MATRIX);

        } else {
            mScaleType = type;
            if (onDrawReady) {
                setZoom(this);
            }
        }
    }

    @Override
    public ScaleType getScaleType() {
        return mScaleType;
    }

    public boolean isZoomed() {
        return normalizedScale != 1;
    }


    public RectF getZoomedRect() {
        if (mScaleType == ScaleType.FIT_XY) {
            throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
        }
        PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
        PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);

        float w = getDrawable().getIntrinsicWidth();
        float h = getDrawable().getIntrinsicHeight();
        return new RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);
    }


    private void savePreviousImageValues() {
        if (matrix != null && viewHeight != 0 && viewWidth != 0) {
            matrix.getValues(m);
            prevMatrix.setValues(m);
            prevMatchViewHeight = matchViewHeight;
            prevMatchViewWidth = matchViewWidth;
            prevViewHeight = viewHeight;
            prevViewWidth = viewWidth;
        }
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable("instanceState", super.onSaveInstanceState());
        bundle.putFloat("saveScale", normalizedScale);
        bundle.putFloat("matchViewHeight", matchViewHeight);
        bundle.putFloat("matchViewWidth", matchViewWidth);
        bundle.putInt("viewWidth", viewWidth);
        bundle.putInt("viewHeight", viewHeight);
        matrix.getValues(m);
        bundle.putFloatArray("matrix", m);
        bundle.putBoolean("imageRendered", imageRenderedAtLeastOnce);
        return bundle;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            normalizedScale = bundle.getFloat("saveScale");
            m = bundle.getFloatArray("matrix");
            prevMatrix.setValues(m);
            prevMatchViewHeight = bundle.getFloat("matchViewHeight");
            prevMatchViewWidth = bundle.getFloat("matchViewWidth");
            prevViewHeight = bundle.getInt("viewHeight");
            prevViewWidth = bundle.getInt("viewWidth");
            imageRenderedAtLeastOnce = bundle.getBoolean("imageRendered");
            super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
            return;
        }

        super.onRestoreInstanceState(state);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        onDrawReady = true;
        imageRenderedAtLeastOnce = true;
        if (delayedZoomVariables != null) {
            setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY, delayedZoomVariables.scaleType);
            delayedZoomVariables = null;
        }
        super.onDraw(canvas);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        savePreviousImageValues();
    }

    /**
     * Get the max zoom multiplier.
     * @return max zoom multiplier.
     */
    public float getMaxZoom() {
        return maxScale;
    }

    /**
     * Set the max zoom multiplier. Default value: 3.
     * @param max max zoom multiplier.
     */
    public void setMaxZoom(float max) {
        maxScale = max;
        superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
    }

    /**
     * Get the min zoom multiplier.
     * @return min zoom multiplier.
     */
    public float getMinZoom() {
        return minScale;
    }

    /**
     * Get the current zoom. This is the zoom relative to the initial
     * scale, not the original resource.
     * @return current zoom multiplier.
     */
    public float getCurrentZoom() {
        return normalizedScale;
    }


    public void setMinZoom(float min) {
        minScale = min;
        superMinScale = SUPER_MIN_MULTIPLIER * minScale;
    }


    public void resetZoom() {
        normalizedScale = 1;
        fitImageToView();
    }


    public void setZoom(float scale) {
        setZoom(scale, 0.5f, 0.5f);
    }

  
    public void setZoom(float scale, float focusX, float focusY) {
        setZoom(scale, focusX, focusY, mScaleType);
    }

    public void setZoom(float scale, float focusX, float focusY, ScaleType scaleType) {
  
        if (!onDrawReady) {
            delayedZoomVariables = new ZoomVariables(scale, focusX, focusY, scaleType);
            return;
        }

        if (scaleType != mScaleType) {
            setScaleType(scaleType);
        }
        resetZoom();
        scaleImage(scale, viewWidth / 2, viewHeight / 2, true);
        matrix.getValues(m);
        m[Matrix.MTRANS_X] = -((focusX * getImageWidth()) - (viewWidth * 0.5f));
        m[Matrix.MTRANS_Y] = -((focusY * getImageHeight()) - (viewHeight * 0.5f));
        matrix.setValues(m);
        fixTrans();
        setImageMatrix(matrix);
    }


    public void setZoom(TouchImageView img) {
        PointF center = img.getScrollPosition();
        setZoom(img.getCurrentZoom(), center.x, center.y, img.getScaleType());
    }

    public PointF getScrollPosition() {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            return null;
        }
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();

        PointF point = transformCoordTouchToBitmap(viewWidth / 2, viewHeight / 2, true);
        point.x /= drawableWidth;
        point.y /= drawableHeight;
        return point;
    }

    public void setScrollPosition(float focusX, float focusY) {
        setZoom(normalizedScale, focusX, focusY);
    }

    /**
     * Performs boundary checking and fixes the image matrix if it
     * is out of bounds.
     */
    private void fixTrans() {
        matrix.getValues(m);
        float transX = m[Matrix.MTRANS_X];
        float transY = m[Matrix.MTRANS_Y];

        float fixTransX = getFixTrans(transX, viewWidth, getImageWidth());
        float fixTransY = getFixTrans(transY, viewHeight, getImageHeight());

        if (fixTransX != 0 || fixTransY != 0) {
            matrix.postTranslate(fixTransX, fixTransY);
        }
    }


    private void fixScaleTrans() {
        fixTrans();
        matrix.getValues(m);
        if (getImageWidth() < viewWidth) {
            m[Matrix.MTRANS_X] = (viewWidth - getImageWidth()) / 2;
        }

        if (getImageHeight() < viewHeight) {
            m[Matrix.MTRANS_Y] = (viewHeight - getImageHeight()) / 2;
        }
        matrix.setValues(m);
    }

    private float getFixTrans(float trans, float viewSize, float contentSize) {
        float minTrans, maxTrans;

        if (contentSize <= viewSize) {
            minTrans = 0;
            maxTrans = viewSize - contentSize;

        } else {
            minTrans = viewSize - contentSize;
            maxTrans = 0;
        }

        if (trans < minTrans)
            return -trans + minTrans;
        if (trans > maxTrans)
            return -trans + maxTrans;
        return 0;
    }

    private float getFixDragTrans(float delta, float viewSize, float contentSize) {
        if (contentSize <= viewSize) {
            return 0;
        }
        return delta;
    }

    private float getImageWidth() {
        return matchViewWidth * normalizedScale;
    }

    private float getImageHeight() {
        return matchViewHeight * normalizedScale;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Drawable drawable = getDrawable();
        if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
            setMeasuredDimension(0, 0);
            return;
        }

        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        viewWidth = setViewSize(widthMode, widthSize, drawableWidth);
        viewHeight = setViewSize(heightMode, heightSize, drawableHeight);

        fitImageToView();
    }


    private void fitImageToView() {
        Drawable drawable = getDrawable();
        if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
            return;
        }
        if (matrix == null || prevMatrix == null) {
            return;
        }

        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();

        float scaleX = (float) viewWidth / drawableWidth;
        float scaleY = (float) viewHeight / drawableHeight;

        switch (mScaleType) {
            case CENTER:
                scaleX = scaleY = 1;
                break;

            case CENTER_CROP:
                scaleX = scaleY = Math.max(scaleX, scaleY);
                break;

            case CENTER_INSIDE:
                scaleX = scaleY = Math.min(1, Math.min(scaleX, scaleY));

            case FIT_CENTER:
                scaleX = scaleY = Math.min(scaleX, scaleY);
                break;

            case FIT_XY:
                break;

            default:
         
                throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");

        }

  
        float redundantXSpace = viewWidth - (scaleX * drawableWidth);
        float redundantYSpace = viewHeight - (scaleY * drawableHeight);
        matchViewWidth = viewWidth - redundantXSpace;
        matchViewHeight = viewHeight - redundantYSpace;
        if (!isZoomed() && !imageRenderedAtLeastOnce) {
     
            matrix.setScale(scaleX, scaleY);
            matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
            normalizedScale = 1;

        } else {
    
            if (prevMatchViewWidth == 0 || prevMatchViewHeight == 0) {
                savePreviousImageValues();
            }

            prevMatrix.getValues(m);

     
            m[Matrix.MSCALE_X] = matchViewWidth / drawableWidth * normalizedScale;
            m[Matrix.MSCALE_Y] = matchViewHeight / drawableHeight * normalizedScale;

   
            float transX = m[Matrix.MTRANS_X];
            float transY = m[Matrix.MTRANS_Y];

            float prevActualWidth = prevMatchViewWidth * normalizedScale;
            float actualWidth = getImageWidth();
            translateMatrixAfterRotate(Matrix.MTRANS_X, transX, prevActualWidth, actualWidth, prevViewWidth, viewWidth, drawableWidth);

            float prevActualHeight = prevMatchViewHeight * normalizedScale;
            float actualHeight = getImageHeight();
            translateMatrixAfterRotate(Matrix.MTRANS_Y, transY, prevActualHeight, actualHeight, prevViewHeight, viewHeight, drawableHeight);

            //
            // Set the matrix to the adjusted scale and translate values.
            //
            matrix.setValues(m);
        }
        fixTrans();
        setImageMatrix(matrix);
    }


    private int setViewSize(int mode, int size, int drawableWidth) {
        int viewSize;
        switch (mode) {
            case MeasureSpec.EXACTLY:
                viewSize = size;
                break;

            case MeasureSpec.AT_MOST:
                viewSize = Math.min(drawableWidth, size);
                break;

            case MeasureSpec.UNSPECIFIED:
                viewSize = drawableWidth;
                break;

            default:
                viewSize = size;
                break;
        }
        return viewSize;
    }

    private void translateMatrixAfterRotate(int axis, float trans, float prevImageSize, float imageSize, int prevViewSize, int viewSize, int drawableSize) {
        if (imageSize < viewSize) {
    
            m[axis] = (viewSize - (drawableSize * m[Matrix.MSCALE_X])) * 0.5f;

        } else if (trans > 0) {
       
            m[axis] = -((imageSize - viewSize) * 0.5f);

        } else {
  
            float percentage = (Math.abs(trans) + (0.5f * prevViewSize)) / prevImageSize;
            m[axis] = -((percentage * imageSize) - (viewSize * 0.5f));
        }
    }

    private void setState(State state) {
        this.state = state;
    }

    public boolean canScrollHorizontallyFroyo(int direction) {
        return canScrollHorizontally(direction);
    }

    @Override
    public boolean canScrollHorizontally(int direction) {
        matrix.getValues(m);
        float x = m[Matrix.MTRANS_X];

        if (getImageWidth() < viewWidth) {
            return false;

        } else if (x >= -1 && direction < 0) {
            return false;

        } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
            return false;
        }

        return true;
    }


    private class GestureListener extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e)
        {
            if(doubleTapListener != null) {
                return doubleTapListener.onSingleTapConfirmed(e);
            }
            return performClick();
        }

        @Override
        public void onLongPress(MotionEvent e)
        {
            performLongClick();
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
        {
            if (fling != null) {
       
                fling.cancelFling();
            }
            fling = new Fling((int) velocityX, (int) velocityY);
            compatPostOnAnimation(fling);
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            boolean consumed = false;
            if(doubleTapListener != null) {
                consumed = doubleTapListener.onDoubleTap(e);
            }
            if (state == State.NONE) {
                float targetZoom = (normalizedScale == minScale) ? maxScale : minScale;
                DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, e.getX(), e.getY(), false);
                compatPostOnAnimation(doubleTap);
                consumed = true;
            }
            return consumed;
        }

        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            if(doubleTapListener != null) {
                return doubleTapListener.onDoubleTapEvent(e);
            }
            return false;
        }
    }

    public interface OnTouchImageViewListener {
        public void onMove();
    }

    private class PrivateOnTouchListener implements OnTouchListener {

        private PointF last = new PointF();

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            mScaleDetector.onTouchEvent(event);
            mGestureDetector.onTouchEvent(event);
            PointF curr = new PointF(event.getX(), event.getY());

            if (state == State.NONE || state == State.DRAG || state == State.FLING) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        last.set(curr);
                        if (fling != null)
                            fling.cancelFling();
                        setState(State.DRAG);
                        break;

                    case MotionEvent.ACTION_MOVE:
                        if (state == State.DRAG) {
                            float deltaX = curr.x - last.x;
                            float deltaY = curr.y - last.y;
                            float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth());
                            float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight());
                            matrix.postTranslate(fixTransX, fixTransY);
                            fixTrans();
                            last.set(curr.x, curr.y);
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_POINTER_UP:
                        setState(State.NONE);
                        break;
                }
            }

            setImageMatrix(matrix);

            if(userTouchListener != null) {
                userTouchListener.onTouch(v, event);
            }

        
            if (touchImageViewListener != null) {
                touchImageViewListener.onMove();
            }
   
            return true;
        }
    }


    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            setState(State.ZOOM);
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true);

            if (touchImageViewListener != null) {
                touchImageViewListener.onMove();
            }
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            super.onScaleEnd(detector);
            setState(State.NONE);
            boolean animateToZoomBoundary = false;
            float targetZoom = normalizedScale;
            if (normalizedScale > maxScale) {
                targetZoom = maxScale;
                animateToZoomBoundary = true;

            } else if (normalizedScale < minScale) {
                targetZoom = minScale;
                animateToZoomBoundary = true;
            }

            if (animateToZoomBoundary) {
                DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, viewWidth / 2, viewHeight / 2, true);
                compatPostOnAnimation(doubleTap);
            }
        }
    }

    private void scaleImage(double deltaScale, float focusX, float focusY, boolean stretchImageToSuper) {

        float lowerScale, upperScale;
        if (stretchImageToSuper) {
            lowerScale = superMinScale;
            upperScale = superMaxScale;

        } else {
            lowerScale = minScale;
            upperScale = maxScale;
        }

        float origScale = normalizedScale;
        normalizedScale *= deltaScale;
        if (normalizedScale > upperScale) {
            normalizedScale = upperScale;
            deltaScale = upperScale / origScale;
        } else if (normalizedScale < lowerScale) {
            normalizedScale = lowerScale;
            deltaScale = lowerScale / origScale;
        }

        matrix.postScale((float) deltaScale, (float) deltaScale, focusX, focusY);
        fixScaleTrans();
    }

    private class DoubleTapZoom implements Runnable {

        private long startTime;
        private static final float ZOOM_TIME = 500;
        private float startZoom, targetZoom;
        private float bitmapX, bitmapY;
        private boolean stretchImageToSuper;
        private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
        private PointF startTouch;
        private PointF endTouch;

        DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean stretchImageToSuper) {
            setState(State.ANIMATE_ZOOM);
            startTime = System.currentTimeMillis();
            this.startZoom = normalizedScale;
            this.targetZoom = targetZoom;
            this.stretchImageToSuper = stretchImageToSuper;
            PointF bitmapPoint = transformCoordTouchToBitmap(focusX, focusY, false);
            this.bitmapX = bitmapPoint.x;
            this.bitmapY = bitmapPoint.y;

            startTouch = transformCoordBitmapToTouch(bitmapX, bitmapY);
            endTouch = new PointF(viewWidth / 2, viewHeight / 2);
        }

        @Override
        public void run() {
            float t = interpolate();
            double deltaScale = calculateDeltaScale(t);
            scaleImage(deltaScale, bitmapX, bitmapY, stretchImageToSuper);
            translateImageToCenterTouchPosition(t);
            fixScaleTrans();
            setImageMatrix(matrix);

            if (touchImageViewListener != null) {
                touchImageViewListener.onMove();
            }

            if (t < 1f) {
       
                compatPostOnAnimation(this);

            } else {
         
                setState(State.NONE);
            }
        }

   
        private void translateImageToCenterTouchPosition(float t) {
            float targetX = startTouch.x + t * (endTouch.x - startTouch.x);
            float targetY = startTouch.y + t * (endTouch.y - startTouch.y);
            PointF curr = transformCoordBitmapToTouch(bitmapX, bitmapY);
            matrix.postTranslate(targetX - curr.x, targetY - curr.y);
        }

 
        private float interpolate() {
            long currTime = System.currentTimeMillis();
            float elapsed = (currTime - startTime) / ZOOM_TIME;
            elapsed = Math.min(1f, elapsed);
            return interpolator.getInterpolation(elapsed);
        }


        private double calculateDeltaScale(float t) {
            double zoom = startZoom + t * (targetZoom - startZoom);
            return zoom / normalizedScale;
        }
    }

   
    private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) {
        matrix.getValues(m);
        float origW = getDrawable().getIntrinsicWidth();
        float origH = getDrawable().getIntrinsicHeight();
        float transX = m[Matrix.MTRANS_X];
        float transY = m[Matrix.MTRANS_Y];
        float finalX = ((x - transX) * origW) / getImageWidth();
        float finalY = ((y - transY) * origH) / getImageHeight();

        if (clipToBitmap) {
            finalX = Math.min(Math.max(finalX, 0), origW);
            finalY = Math.min(Math.max(finalY, 0), origH);
        }

        return new PointF(finalX , finalY);
    }


    private PointF transformCoordBitmapToTouch(float bx, float by) {
        matrix.getValues(m);
        float origW = getDrawable().getIntrinsicWidth();
        float origH = getDrawable().getIntrinsicHeight();
        float px = bx / origW;
        float py = by / origH;
        float finalX = m[Matrix.MTRANS_X] + getImageWidth() * px;
        float finalY = m[Matrix.MTRANS_Y] + getImageHeight() * py;
        return new PointF(finalX , finalY);
    }

    private class Fling implements Runnable {

        CompatScroller scroller;
        int currX, currY;

        Fling(int velocityX, int velocityY) {
            setState(State.FLING);
            scroller = new CompatScroller(context);
            matrix.getValues(m);

            int startX = (int) m[Matrix.MTRANS_X];
            int startY = (int) m[Matrix.MTRANS_Y];
            int minX, maxX, minY, maxY;

            if (getImageWidth() > viewWidth) {
                minX = viewWidth - (int) getImageWidth();
                maxX = 0;

            } else {
                minX = maxX = startX;
            }

            if (getImageHeight() > viewHeight) {
                minY = viewHeight - (int) getImageHeight();
                maxY = 0;

            } else {
                minY = maxY = startY;
            }

            scroller.fling(startX, startY, (int) velocityX, (int) velocityY, minX,
                    maxX, minY, maxY);
            currX = startX;
            currY = startY;
        }

        public void cancelFling() {
            if (scroller != null) {
                setState(State.NONE);
                scroller.forceFinished(true);
            }
        }

        @Override
        public void run() {

     
            if (touchImageViewListener != null) {
                touchImageViewListener.onMove();
            }

            if (scroller.isFinished()) {
                scroller = null;
                return;
            }

            if (scroller.computeScrollOffset()) {
                int newX = scroller.getCurrX();
                int newY = scroller.getCurrY();
                int transX = newX - currX;
                int transY = newY - currY;
                currX = newX;
                currY = newY;
                matrix.postTranslate(transX, transY);
                fixTrans();
                setImageMatrix(matrix);
                compatPostOnAnimation(this);
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    private class CompatScroller {
        Scroller scroller;
        OverScroller overScroller;
        boolean isPreGingerbread;

        public CompatScroller(Context context) {
            if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
                isPreGingerbread = true;
                scroller = new Scroller(context);

            } else {
                isPreGingerbread = false;
                overScroller = new OverScroller(context);
            }
        }

        public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
            if (isPreGingerbread) {
                scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
            } else {
                overScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
            }
        }

        public void forceFinished(boolean finished) {
            if (isPreGingerbread) {
                scroller.forceFinished(finished);
            } else {
                overScroller.forceFinished(finished);
            }
        }

        public boolean isFinished() {
            if (isPreGingerbread) {
                return scroller.isFinished();
            } else {
                return overScroller.isFinished();
            }
        }

        public boolean computeScrollOffset() {
            if (isPreGingerbread) {
                return scroller.computeScrollOffset();
            } else {
                overScroller.computeScrollOffset();
                return overScroller.computeScrollOffset();
            }
        }

        public int getCurrX() {
            if (isPreGingerbread) {
                return scroller.getCurrX();
            } else {
                return overScroller.getCurrX();
            }
        }

        public int getCurrY() {
            if (isPreGingerbread) {
                return scroller.getCurrY();
            } else {
                return overScroller.getCurrY();
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void compatPostOnAnimation(Runnable runnable) {
        if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
            postOnAnimation(runnable);

        } else {
            postDelayed(runnable, 1000/60);
        }
    }

    private class ZoomVariables {
        public float scale;
        public float focusX;
        public float focusY;
        public ScaleType scaleType;

        public ZoomVariables(float scale, float focusX, float focusY, ScaleType scaleType) {
            this.scale = scale;
            this.focusX = focusX;
            this.focusY = focusY;
            this.scaleType = scaleType;
        }
    }

    private void printMatrixInfo() {
        float[] n = new float[9];
        matrix.getValues(n);
        Log.d(DEBUG, "Scale: " + n[Matrix.MSCALE_X] + " TransX: " + n[Matrix.MTRANS_X] + " TransY: " + n[Matrix.MTRANS_Y]);
    }
}

ensuite pour créer un effet zoom avec ma méthode il faut ajouter enfin éditer votre fichier Layout XML en rapport avec votre activité ou se ttrouve l’image en question et instancier la classe ajouté précédemment en remplaçant les balises classiques <ImageView></ImageView> par celle de la nouvelle classe ajouté précédemment : <com.maxou.projet.TouchImageView></com.maxou.projet.TouchImageView>

donc ceci :

  <ImageView
        android:id="@+id/camerap"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000000" >
    </ImageView>

devient cela :

  <com.maxou.projet.TouchImageView
        android:id="@+id/camerap"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000000" >
    </com.maxou.projet.TouchImageView>

Et voila, vous avez désormais un zoom sur votre photo 🙂 .

Merci d’avoir lu Développement android zoom imageview java

bonne journée.

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Calendrier de pêche lunaire (lunar calendar)

Calendrier de pêche lunaire (Lunar Fishing Calendar)

calendrier de pêche lunaire

Calenderier de Pêche Lunaire

Calendrier de pêche lunaire (Lunar Fishing Calendar) gratuit.

Un calendrier de pêche lunaire statique pour prévoir vos sessions de pêche par rapport à l’activité lunaire.

la Lune influencerait la prise des poissons.

Certains facteurs (les heures du lever et coucher du Soleil et de la Lune, et les phases de la Lune) sont à prendre en compte pour la préparation d’une session de pêche. Ces facteurs sont indiqués dans ce calendrier : (Null, Normal, Bon, Excellent)

Bonne pêche à tous avec le Calendrier de pêche lunaire

Télécharger gratuitement ce Calendrier de Pêche Lunaire

calendrier de pêche lunaire

Télécharger gratuitement ce Calendrier de Pêche Lunaire sur Google Play Store

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Géo localisation – Traceur GPS Personnel Tracker

 Géo localisation Traceur GPS Personnel Tracker

logiciel Traceur GPS Personnel

Géo localisation – Traceur GPS Personnel

Geolocalisation traceur GPS automatique personnel, suivez vos déplacement ou celui de vos enfants avec ce tracker gps.

Ce traceur GPS permet d’enregistrer votre position GPS automatiquement. Depuis les paramètres du logiciel vous pouvez régler le temps en minute de la localisation automatique et à la fin de la journée visualiser votre trajet sur la carte google map ou de manière individuel pour chaque localisation depuis la section Log.Vous avez la possibilité de modifier le type de carte selon vos besoin pour mieux voir votre emplacement dans l’espace et le temps enfin sur terre.Pratique pour voir emplacement quotidien de son enfant par exemple.

Un tracker GPS simple , rapide et gratuit.

application gratuite traceur GPS

Télécharger Geolocalisation Traceur GPS

geolocation traceur gps

geo location tracker gps gratuit

traceur gps

tracker gps

 

gps traceur tracker gratuit

Télécharger Géo localisation Traceur GPS sur Google PLay Store

bonne pêche à tous

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Rencontres Amitié Dating tchat gratuit

Rencontres Amitié Dating tchat gratuit

application de rencontres

Application rencontre & amitié tchat

Réseau d’amitié et rencontre  -> Rencontres Amitié Dating tchat gratuit.
(connexion uniquement avec un profil facebook )

Rencontres & Amitié Dating tchat gratuit Une application gratuite pour discuter, faire connaissance, se faire des amis et pourquoi pas trouver l’amour pour les célibataires.Amitié ou Amour  ou Rencontres pas de pression.
Des personnes de la terre entière.
Géo localisation des utilisateur par la distance, message chat, requête d’amitié, carouselle pour trouver de nouveaux amis comme la plupart des sies de rencontes.
Que vous chercher un simple amis ou une relation amoureuse téléchargez l’application et attendre l’âme sœur ou un ami .Chercher vos futurs amis ou votre moitié.

Bon Tchat à tous et bonne rencontres c’est gratuit

Télécharger gratuitement cette application de Rencontres

Rencontres Amitié Dating tchat gratuit

rencontres

rencontres tchat

application rencontres

Télécharger gratuitement Dating Rencontres & Amitié sur Play Store

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Geo Champignon mycologie cueilleur cueillette champignons

Geo Champignon mycologie cueilleur cueillette champignons

geo champignon

geo mushroom

Geo Champginon (Geo mushroom) une application pour géolocaliser, localiser vos coins à champignons, créer vos races, vos espèces de champignon selon votre région ou votre cueillette, il y a un chat intégré entre cueilleurs de champignons, vous pouvez voir les cueillettes partagés par les utilisateurs de l’application tout cela gratuitement, Geo Champignon (geo mushroom) pour les cueilleur champignon et la mycologie.

Sauvegarder vos coins à champignon grâce au GPS (latitude,longitude). Tous vos coins et vos cueillettes de champignons référencé sur la même  google map avec vos photos, vos spots à champignon !!

Regarder les publications des autres cueilleurs qui publient des photos de champignons, Bolet, Cèpe, Trompette de la mort, Pied de mouton, Girolles etc…  avec possibilité de commentaires pour le social entre cueilleurs et se renseigner sur les champignons et la mycologie.

Bonne cueillette de champignons à tous

Télécharger gratuitement cette application geo champignon mushroom

geo mushroom cueillette

geo champignon application android

geo champignon, pied de mouton, trompette de la mort, bolet, cèpe

cueillette champignon

Geo Champignon (geo mushroom) cueilleur champignon

Télécharger gratuitement geo champignon (geomushroom) sur Play Store

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Pêche Poisson Compteur journal de pêche carnet pour pêcheur

Pêche Poisson Compteur journal de pêche carnet pour pêcheur

journal de pêche

Pêche Poisson Compteur

Pêche Poissons Compteur une application gratuite pour les pêcheurs de poissons et amoureux de la pêche.De multiples outils sont disponibles pour vous aider à améliorer, classifier, cataloguer votre pêche.
A la manière d’un journal de pêche personnel ou d’un carnet de pêche numérique mémoriser vos sessions et vos prises de pêches facilement.La longueur, le poids, la date, l’heure, la méthode utilisée, l’image du poisson et même ses coordonnées GPS pour le visualiser directement sur la carte google map.

Pêche Poisson Compteur journal de pêche carnet pour pêcheur possède un menu avec des icône ou un menu avec des photos au choix !!
Créer vos races de poissons selon votre contexte, votre lieu géographique ou votre pêche personnel.
A force de renseigner vos poissons sur la carte, vous voyer vos meilleurs coins selon les espèces par exemple….
Pour tout type de pêche, vous avez la possibilité de pouvoir utiliser un menu photo désormais à la places des icônes donc pour tous les poissons du monde.
Pour les pêcheurs au coup il existe l’option poisson rapide, ajoutez en un clic (comme un compteur) un poisson ou plusieurs sans forcément prendre une photo, inutile lorsque qu’on pêche le goujon ou l’ablette.
Vous pouvez voir les poissons publier par les autres pêcheurs dans la section voir des poissons, il y a aussi un classement entre pêcheur facultatif, un calendrier de pêche lunaire, et une section vidéo pour ajouter des liens youtubes.

Brochet, Carpe commune, Silure, Perche, Black bass, Thon, Requin vous pouvez créer toutes les races

le carnet de pêche numérique !

Voir aussi mon autre application de pêche : FISHING UTILITY

bonne pêche à tous

Télécharger Pêche Poisson Compteur journal pour les pêcheurs

pêche journal

Pêche Poisson Compteur journal (carnet) pêcheurs

pêche poisson compteur

poisson compteur

Pêche Poisson Compteur journal (carnet) pour les pêcheurs

journal de pêche

Télécharger Pêche Poisson Compteur pour les pêcheurs sur Google PLay Store

bonne pêche à tous

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Geo Detector détecteur de métaux numismate trésor

Geo Detector détecteur de métaux numismate trésor

geo detector pour detectoriste

geo detector

Geo Detector détecteur de métaux, numismate, chasseur de trésor une application pour les personnes qui cherchent des trésors, détectoristes (détection), avec des détecteur de métaux.

Geo Detector pour détecteur de métal, numismate, chercheur de trésor pour les passionnés d’archéologie et d’histoire.
Cette application de géolocalisation d’objet peut servir pour mémoriser ses découvertes de trésor.Par exemple représenter sur la carte google map tous vos objets découverts et donc cela vous donnera une bonne idée pour continuer à chercher, de bons indices…
Sauvegarder la latitude, la longitude de vos découvertes, son image et sa description dans votre base de données grâce au GPS.

Geo detector une application gratuite avec un Chat intégré pour mettre en relation les découvreurs de trésor, numismate.
Pratique vous pouvez partagés vos découvertes avec les autres utilisateurs et voir leurs découvertes et donc apprendre surtout pour les numismates.

Les Experts de la découverte de trésor partagent leurs matériels, leurs bonnes pratiques et la photo de leurs joyaux bien souvent.Apprenez des plus grand, renseignez vous sur les techniques les plus efficaces de la détection.

Pour le FUN, le classement des meilleurs chasseurs de trésors.

Bonne découvertes et bonne chasse au trésors à tous avec vos détecteur de métaux.

Télécharger GEO DETECTOR gratuitement sur google play store

geo detector application

deo detector détecteur de metal

Geo Detector détecteur de métaux numismate trésor

logiciel détecteur de métaux

 

Télécharger GEODETECTOR gratuitement sur google play store

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Pêche Poissons Compteur Pro

Pêche Poissons Compteur pro

logiciel de pêche pêche poisson compteur

Pêche poissons compteur pro sans publicités
(pêche poisson compteur (ancienne version))

Pêche Poissons Compteur version gratuite ici

Application pour les pêcheurs amoureux de la pêche.De multiples outils sont disponibles pour vous aider à améliorer , classifier, cataloguer votre pêche.
A la manière d’un journal personnel, mémoriser vos sessions et vos prises de pêches facilement.La longueur, le poids, la date, l’heure, la méthode utilisée, l’image du poisson et même ses coordonnées GPS pour le visualiser directement sur la carte.
Pour tout type de pêche, vous avez la possibilité de pouvoir utiliser un menu photo désormais à la places des icônes donc pour tous les poissons du monde.
Calendrier de pêche lunaire intégré.
Tchat intégré entre pêcheur, calendrier de pêche lunaire.
Pour les pêcheurs au coup il existe l’option poisson rapide, ajoutez en un clic un poisson ou plusieurs sans forcément prendre une photo ou ses coordonnées GPS, inutile lorsque qu’on pêche le goujon.
Bonne pêche à tous

Télécharger Pêche Poisson Compteur 

pêche poissons compteur

pêche poisson compteur

pêche poisson compteur

pêche poisson compteur google map pêche poisson compteur google map

Télécharger Pêche Poisson Compteur Pro 

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Fishing journal de pêche pour pêcheur

Fishing journal de pêche pour pêcheur

Fishing Utility journal de pêche application

Fishing  journal de pêche application (carnet de pêche) pour pêcheur gratuit.

Fishing Utility  pour les vrais pêcheurs ! Plutôt orienté pour les grosses pêche avec de gros poissons, (comme la pêche au leurre ou en bateau) à la différence de pêche poisson compteur mon autre application qui est adapté à toutes les types de pêche exemple : la pêche au coup et aux petits poissons grâce à son compteur de poissons rapide.

Fishing journal intègre un brin de réseau social entre pêcheur pour la convivialité et pour apprendre de nouvelles techniques de pêche partagés par les pêcheurs.Un outils fiable pour référencer vos prises, localiser vos poissons sur google map et mémoriser leurs caractéristiques (latitude,longitude,longueur,poids,date,heure et image) rapidement et facilement comme un carnet de pêche à l’ancienne.

Vous pouvez créer toutes les espèces de poissons selon votre pêche.Exemple, vous pêchez le brochet, la carpe ou la dorade … facile créer vos races personnalisés simplement et rapidement.

Fishing journal de pêche permet de partager vos photos de poisson avec les autres utilisateurs du logiciel,  ainsi que la méthode utilisé comme je le disais pour le social entre pêcheur et la convivialité avec les commentaires sur les photos partagés.

Fishing carnet de pêche possède un Chat pour discuter avec les autres pêcheurs, un calendrier de pêche lunaire et un classement automatique pour voir les meilleurs pêcheurs et quel type de poisson ils pêchent.

Pratique de géolocaliser vos spots de pêche, vos prises et tout voir sur la carte ainsi que voir les techniques partagés par les autres utilisateurs en commentaire pour améliorer sa passion.
(Je précise qu’aucune coordonnées GPS ne sont partagés ni publiés, les coordonnées restent confidentielles)

Application de pêche optimisé pour la rapidité et peu gourmande en ressource.

A La différences des autres applications on en récupère aucune de vos données !!

A essayer tout simplement c’est totalement gratuit !

Disponible sur Google Play Store

good fishing all

 

Téléchargez Gratuitement Fishing Utility

Fishing Utility application pêche

Fishing Utility journal de pêche application

Fishing Utility journal pêche

Fishing Utility

Fishing Utility journal pêcheFishing Utility journal de pêche

Téléchargez Gratuitement Fishing Utility sur Google Play Store

 

Share this...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone