2

I'm using eclipse.

I'm having problem with getting the image in the center with matrix scale type.

I mean that I want to have the matrix scale type and also have the image in the center ... to put it simply when I run the app for the first time it's image is scale and is in the left side of the screen

I want that when I'm running the app for the first time ..have the image in the center of view with no scales.

Now my first screen looks like this..

enter image description here

I want it to look like this..

enter image description here

  • have also tied these topics but couldn't find any solution.

Fit to Android Imageview Matrix Center of Screen

Scale and center matrix on arbitrary point

How to use scaletype of a ImageView as center and matrix at the sametime?

And this is my code...

public class MainActivity extends Activity {

   private ImageView img;
   private Matrix matrix = new Matrix();
   private float scale = 1f;
   private ScaleGestureDetector SGD;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      img = (ImageView)findViewById(R.id.imageView1);
      SGD = new ScaleGestureDetector(this,new ScaleListener());

   }


   @Override
   public boolean onTouchEvent(MotionEvent ev) {
      SGD.onTouchEvent(ev);
      return true;
   }

   private class ScaleListener extends ScaleGestureDetector.
   SimpleOnScaleGestureListener {
   @Override
   public boolean onScale(ScaleGestureDetector detector) {
      scale *= detector.getScaleFactor();
      scale = Math.max(0.1f, Math.min(scale, 5.0f));
      matrix.setScale(scale, scale);
      img.setImageMatrix(matrix);
      return true;
   }
}

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }

Layout XML :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:scaleType="matrix"
    android:src="@drawable/gh" />

</RelativeLayout>
Community
  • 1
  • 1

3 Answers3

9

The Better solution is to make a custom ImageView

public class TouchImageView extends ImageView {

    Matrix matrix;

    // We can be in one of these 3 states
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    int mode = NONE;

    // Remember some things for zooming
    PointF last = new PointF();
    PointF start = new PointF();
    float minScale = -3f;
    float maxScale = 3f;
    float[] m;

    int viewWidth, viewHeight;
    static final int CLICK = 3;
    float saveScale = 1f;
    protected float origWidth, origHeight;
    int oldMeasuredWidth, oldMeasuredHeight;

    ScaleGestureDetector mScaleDetector;

    Context context;

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

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

    private void sharedConstructing(Context context) {
        super.setClickable(true);
        this.context = context;
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        matrix = new Matrix();
        m = new float[9];
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);

        setOnTouchListener(new OnTouchListener() {

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

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                       last.set(curr);
                        start.set(last);
                        mode = DRAG;
                        break;

                    case MotionEvent.ACTION_MOVE:
                        if (mode == DRAG) {
                            float deltaX = curr.x - last.x;
                            float deltaY = curr.y - last.y;
                            float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);
                            float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);
                            matrix.postTranslate(fixTransX, fixTransY);
                            fixTrans();
                            last.set(curr.x, curr.y);
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                        mode = NONE;
                        int xDiff = (int) Math.abs(curr.x - start.x);
                        int yDiff = (int) Math.abs(curr.y - start.y);
                        if (xDiff < CLICK && yDiff < CLICK)
                            performClick();
                        break;

                    case MotionEvent.ACTION_POINTER_UP:
                        mode = NONE;
                        break;
                }

                setImageMatrix(matrix);
                invalidate();
                return true; // indicate event was handled
            }

        });
    }

    public void setMaxZoom(float x) {
        maxScale = x;
    }

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

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float mScaleFactor = detector.getScaleFactor();
            float origScale = saveScale;
            saveScale *= mScaleFactor;
            if (saveScale > maxScale) {
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            } else if (saveScale < minScale) {
                saveScale = minScale;
                mScaleFactor = minScale / origScale;
            }

            if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)
                matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);
            else
                matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());

            fixTrans();
            return true;
        }
    }

    void fixTrans() {
        matrix.getValues(m);
        float transX = m[Matrix.MTRANS_X];
        float transY = m[Matrix.MTRANS_Y];

        float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
        float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);

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

    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;
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        viewHeight = MeasureSpec.getSize(heightMeasureSpec);

        //
        // Rescales image on rotation
        //
        if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
                || viewWidth == 0 || viewHeight == 0)
            return;
        oldMeasuredHeight = viewHeight;
        oldMeasuredWidth = viewWidth;

        if (saveScale == 1) {
            //Fit to screen.
            float scale;

            Drawable drawable = getDrawable();
            if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)
                return;
            int bmWidth = drawable.getIntrinsicWidth();
            int bmHeight = drawable.getIntrinsicHeight();

            Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

            float scaleX = (float) viewWidth / (float) bmWidth;
            float scaleY = (float) viewHeight / (float) bmHeight;
            scale = Math.min(scaleX, scaleY);
            matrix.setScale(scale, scale);

            // Center the image
            float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
            float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
            redundantYSpace /= (float) 2;
            redundantXSpace /= (float) 2;

            matrix.postTranslate(redundantXSpace, redundantYSpace);

            origWidth = viewWidth - 2 * redundantXSpace;
            origHeight = viewHeight - 2 * redundantYSpace;
            setImageMatrix(matrix);
        }
        fixTrans();
    }
}

And simply use this TouchImageView

public class MultiTouchActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TouchImageView img = new TouchImageView(this);
        img.setImageResource(R.drawable.img);
        img.setMaxZoom(4f);
        setContentView(img);
    }
}

Hope it will help you :)
Refer this to get more info

Update:

You can work with xml also

add this control wherever you want in the xml file

<com.example.test.TouchImageView
     android:id="@+id/imageViewMy"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/img" 
    />

So you xml will look like :

XML :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <com.example.test.TouchImageView
        android:id="@+id/imageViewMy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img" />

</RelativeLayout>

Activity :

public class MultiTouchActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1);
        TouchImageView img = (TouchImageView) findViewById(R.id.imageViewMy);
        img.setMaxZoom(4f);
    }
}
SweetWisher ツ
  • 7,296
  • 2
  • 30
  • 74
  • use `android:layout_centerInParent= "true"` – SweetWisher ツ Nov 01 '14 at 09:46
  • look at the image ......https://drive.google.com/file/d/0Bz-YU0FsDfp0NGNjMWNKejdILUE/view?usp=sharing – Pouya Parak Octopus Nov 01 '14 at 09:46
  • again it's not in the center...it's still in the left side of the screen ... https://drive.google.com/file/d/0Bz-YU0FsDfp0NGNjMWNKejdILUE/view?usp=sharing.......:(( – Pouya Parak Octopus Nov 01 '14 at 09:52
  • But obvious, it will be changed as you are changing its position with `Gesture` – SweetWisher ツ Nov 01 '14 at 09:56
  • I have recorded a video of my screen ... look at this .. it will hwlp to understand better ..... as you 'll see the image is stick to the left side of the screen ...I want to have it in the middle......https://drive.google.com/file/d/0Bz-YU0FsDfp0bVZfN3RRRmFnblU/view?usp=sharing – Pouya Parak Octopus Nov 01 '14 at 10:11
  • have u added the tag `android:layout_centerInParent= "true"` – SweetWisher ツ Nov 01 '14 at 10:13
  • yes ... my XML is the same as you posted in the answer....I just changed android:layout_width="300dp" to android:layout_width="wrap_content"......But none of them have the proper effect that i wanted – Pouya Parak Octopus Nov 01 '14 at 10:19
  • You need to specify the width..have you ever tried with `300dp` ? – SweetWisher ツ Nov 01 '14 at 10:22
  • @ SweetWisher ツ you need to set the scale type to matrix – Pouya Parak Octopus Nov 01 '14 at 10:29
  • Hey I got your problem.. when you zoom it out..the Image becomes smaller than the imageView size and it shows at left side but when you zoom it out, it will be shwon in center.. The problem is O*ImageView is centered NOT THE IMAGE* – SweetWisher ツ Nov 01 '14 at 10:29
  • I think thats what i mean...but how to set the image in the center of image view???? – Pouya Parak Octopus Nov 01 '14 at 10:36
  • Check ma code. I have tested it and working perfect:) let me know if you face any issue. – SweetWisher ツ Nov 01 '14 at 10:37
  • I'm totally newbie and don't know what the ma code is....I would be glad if you can help me with this.....can you post the code that you menshioned as ma code?????!!! – Pouya Parak Octopus Nov 01 '14 at 10:43
  • Check my answer now. I meant MY code that I posted here as an answer :) – SweetWisher ツ Nov 01 '14 at 10:44
  • I tried it out....it worked great ... but with this codes actualy the default xml designer page in eclipse becomes unused and if for example I want to add a button somewhere in this image I won't be able ....am i right??? – Pouya Parak Octopus Nov 01 '14 at 11:07
  • No..You can use it with xml also :) where ever you want to use it .. I am updating the answer to show you that way – SweetWisher ツ Nov 01 '14 at 11:09
  • thank you my friend....It totally solved my problem...i don't know how to thank you ..... thankssssssssssssssssssssssss – Pouya Parak Octopus Nov 01 '14 at 12:25
  • thank you my friend....It totally solved my problem...i don't know how to thank you ..... thankssssssssssssssssssssssss – Pouya Parak Octopus Nov 01 '14 at 14:52
  • SweetWisher ツ - would you mind sharing info how to handle the click to calculate what location of the drawable (I use a Bitmap there) has been clicked? I understand its a calculation based on last.x, savescale and some other factors yet for some reason have not solved that yet. thanks in advance. – Piotr Nov 13 '14 at 21:41
  • re: above comment - I believe the solution is to catch the initial scaling being done to fit the image to screen (in OnMeasure) and then the calculation is as follows (using initialScale captured during onMeasure): imageX = (clickX-valueFrom_MTRANS_X) / saveScale / initialScale. – Piotr Nov 13 '14 at 23:04
0
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"  
    android:scaleType="matrix"               
    android:src="@drawable/gh" />

</RelativeLayout>

android:layout_centerHorizontal="true" <!-- To take it to center --> android:scaleType="fitXY" <!-- Fit the Image -->

Change layot width and height towrap_content

And Crop image as per the screen size. And store them in different drawable folders

W I Z A R D
  • 1,224
  • 3
  • 17
  • 44
  • thanks for your answer...But I have to set the scale type to matrix in order to have the pinch zoom....I mean I can't change it to "fitXY" in that case I won't have the pinch zoom capability – Pouya Parak Octopus Nov 01 '14 at 10:26
  • then u need to crop the image as per screen size and put them in different drawable folders @PouyaParakOctopus – W I Z A R D Nov 01 '14 at 10:30
0

set width = 512 and height = 300. and image as background try my code. its working

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" 
android:layout_gravity="center">

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="500dp"
    android:layout_height="300dp"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:scaleType="matrix"
    android:background="@drawable/imgg" />

</RelativeLayout>
M S Gadag
  • 2,057
  • 1
  • 12
  • 15
  • thank you ... it was better .... but look at the video that i've recorded/ how can i make it somehow that when I zoom it out i gets to the middle of the screen not the north-west :) of it...https://drive.google.com/file/d/0Bz-YU0FsDfp0UWZhM21SaEloVzQ/view?usp=sharing – Pouya Parak Octopus Nov 01 '14 at 11:20
  • yes...some how !!!! .... there is just one little issue that i mentioned it in previous comment – Pouya Parak Octopus Nov 01 '14 at 12:00