Search code examples
androidimage-scaling

Matrix setScale Function is not working as expected


I have this code for resizing an image : Java :

 public class MainActivity extends Activity {

    private ImageView iv, iv2;
    private float scaley = 1f;
    private float scaley2 = 1f;
    private GestureDetectorCompat detector;
    Matrix m = new Matrix();
    Matrix m2 = new Matrix();
    private RelativeLayout root;

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


        root = (RelativeLayout) findViewById(R.id.root);
        iv = (ImageView) findViewById(R.id.imageView);
        iv2 = (ImageView) findViewById(R.id.imageView2);

        iv.setScaleType(ImageView.ScaleType.MATRIX);
        iv2.setScaleType(ImageView.ScaleType.MATRIX);
        detector = new GestureDetectorCompat(this, new GestureDetector.SimpleOnGestureListener() {

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {


                scaley -= distanceY / root.getHeight();
                m.setScale(1, scaley, 0, 0);
                iv.setImageMatrix(m);


                scaley2 += distanceY / root.getHeight();
                m2.setScale(1, scaley2);
                int imageHeight = iv2.getDrawable().getMinimumHeight();
                m2.postTranslate(0, iv2.getHeight() - (imageHeight * scaley2));
                iv2.setImageMatrix(m2);

              return true;
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return detector.onTouchEvent(event);
    }
}

Layout :

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context=".MainActivity"
    android:id="@+id/root">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/imageView"
            android:layout_alignParentTop="true"
            android:scaleType="fitCenter"
            android:adjustViewBounds="true"

            android:src="@drawable/as" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/imageView"
            android:id="@+id/imageView2"
            android:src="@drawable/as"
            android:scaleType="fitCenter"
            android:adjustViewBounds="true"
            />
</RelativeLayout>

I want my second image to have a pivot on its bottom, so I use this part :

scaley2 += distanceY / root.getHeight();
                m2.setScale(1, scaley2);
                int imageHeight = iv2.getDrawable().getMinimumHeight();
                m2.postTranslate(0, iv2.getHeight() - (imageHeight * scaley2));
                iv2.setImageMatrix(m2); 

It works, image looks anchored at the bottom but, it's not growing, when I try to grow the image, it stays at its default size. How can I fix this? Thanks.


Solution

  • EDIT:

    I found the cleanest way to do this is to have the two ImageViews overlap, then calculate the rectangles that the images should occupy based on the touch event and just set the matrix to map the image bounds to the rectangle bounds, ex:

            // after setting image resource, get the bounds of the bitmap
            Drawable drawable = mImageView1.getDrawable();
            image1Bounds.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
            drawable = mImageView2.getDrawable();
            image2Bounds.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
    
            // use the Y coord of touch event as bottom of imageView1 and top of imageView2
            imageView1Bounds.set(0, 0, mImageView1.getMeasuredWidth(), event.getY());
            imageView2Bounds.set(0, event.getY(), mImageView2.getMeasuredWidth(), mImageView2.getMeasuredHeight());
    
            // set the matrices to transform the images to their respective bounds
            mMatrix1.setRectToRect(image1Bounds, imageView1Bounds, Matrix.ScaleToFit.FILL);
            mMatrix2.setRectToRect(image2Bounds, imageView2Bounds, Matrix.ScaleToFit.FILL);
    
            mImageView1.setImageMatrix(mMatrix1);
            mImageView2.setImageMatrix(mMatrix2);
    

    You can see the entire working project at: https://github.com/klarson2/Matrix


    If you want to anchor the bottom of the image to the bottom of the ImageView, your best bet is to add a translation that will do that.

                Matrix m = new Matrix();
                scaley += distanceY / root.getHeight();
                m.setScale(1, scaley);  // no pivot here
                int imageHeight = iv.getDrawable().getIntrinsicHeight();
                m.postTranslate(0, iv.getHeight() - (imageHeight * scaley));
                iv.setImageMatrix(m);
                return true;
    

    Also I would recommend allocating a new Matrix once during initialization and then reusing that Matrix in onScroll() to improve performance.