Search code examples
xamarin.androidzooming

How to make image zoomable in Xamarin.Android?


I have the following image:

enter image description here

Its dimensions are 1920 X 1901 pixels. On the following link is its real dimension:

https://i.sstatic.net/0rjdP.jpg

I want it to occupy all the space of the screen bellow the toolbar but as it's that big when I put the image in the screen and run the application, when I try to go to the activity the image is in, I got an exception. Apart from wanting to make the image occupy the whole space bellow the toolbar I want when I make the gestures spread and pinch, the image to zoom in and to zoom out respectively.

P.S. I run the application on 5 inches device, but I'm planning to run it on bigger and smaller devices too.


Solution

  • In Xamarin Android ,you can custom Touch event of ImageView to implement it .

    Xml : Adding a ImageView with a sample image :

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    
        <ImageView
            android:id="@+id/main_imgZooming"
            android:background="@color/accent_material_dark"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:scaleType="matrix"
            android:layout_gravity="center"
            android:src="@drawable/imageone"/>
    
    </RelativeLayout>
    

    Then in Activity , you can custom the Touch Event :

    public class MainActivity : AppCompatActivity
    {
        private ImageView view;
    
        private static  int NONE = 0;
        private static  int DRAG = 1;
        private static  int ZOOM = 2;
    
        private int mode = NONE;
        private float oldDist;
        private Matrix matrix = new Matrix();
        private Matrix savedMatrix = new Matrix();
        private PointF start = new PointF();
        private PointF mid = new PointF();
    
        float minScaleR = 0.1f;  //Minimum scaling
        static  float MAX_SCALE = 4f; //Maximum zoom ratio
        //float dist = 1f;
    
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);
    
            /*
            view = FindViewById<ImageView>(Resource.Id.main_imgZooming);
            view.Touch += Img_test_Touch;
    
            matrix.SetScale(minScaleR, minScaleR); //Start zooming out first
    
            var metrics = Resources.DisplayMetrics;
            int screenWidth = metrics.WidthPixels;
    
            matrix.PostTranslate(screenWidth / 4, screenWidth / 2);     //The position of the image is offset by screenWidth/2 pixels from the top left corner of the imageview
            view.ImageMatrix = matrix;
            */
        }
    
        // calculator the distance of two points
        private float distance(MotionEvent eventA)
        {
            float x = eventA.GetX(0) - eventA.GetX(1);
            float y = eventA.GetY(0) - eventA.GetY(1);
            return (float)(System.Math.Sqrt(x * x + y * y));
        }
    
        // calculator the middle point of two points
        private PointF middle(MotionEvent eventB)
        {
            float x = eventB.GetX(0) + eventB.GetX(1);
            float y = eventB.GetY(0) + eventB.GetY(1);
            return new PointF(x / 2, y / 2);
        }
    
    
        private void Img_test_Touch(object sender, Android.Views.View.TouchEventArgs e)
        {
            ImageView view = sender as ImageView;
            switch (e.Event.Action & e.Event.ActionMasked)
            {
                //single finger
                case MotionEventActions.Down:
                    //matrix.Set(view.Matrix);
                    savedMatrix.Set(matrix);
                    start.Set(e.Event.GetX(), e.Event.GetY());
                    mode = DRAG;
                    Console.WriteLine(mode +"---"+ e.Event.GetX());
                break;
    
                //double finger
                case MotionEventActions.PointerDown:
                    oldDist = distance(e.Event);
                    if (oldDist > 10f)
                    {
                        savedMatrix.Set(matrix);
                        middle(e.Event);
                        mode = ZOOM;
                    }
                    Console.WriteLine(mode+"---" + oldDist);
                 break;
                //finger up
                case MotionEventActions.Up:
                case MotionEventActions.PointerUp:
                    mode = NONE;
                    break;
                // finger move
                case MotionEventActions.Move:
                    if (mode == DRAG)
                    {
                        //single finger
                        matrix.Set(savedMatrix);
                        matrix.PostTranslate(e.Event.GetX() - start.X, e.Event.GetY() - start.Y);
                    } else if (mode == ZOOM) {
                        //double finger
                        float newDist = distance(e.Event);
                        if (newDist > 10f) {
                            matrix.Set(savedMatrix);
                            float scale = newDist / oldDist;
                            matrix.PostScale(scale, scale, mid.X, mid.Y);
                        }
                }
                break;
            }
    
            view.ImageMatrix = matrix;
            CheckScale();  //Limit zoom range
            center();
        }
    
        //Limit maximum and minimum scaling
        protected void CheckScale()
        {
            float[] p = new float[9];
            matrix.GetValues(p);
            if (mode == ZOOM)
            {
                if (p[0] < minScaleR)
                {
                    matrix.SetScale(minScaleR, minScaleR);
                }
                if (p[0] > MAX_SCALE)
                {
                    matrix.Set(savedMatrix);
                }
            }
        }
    
    
        //Automatic centering
        protected void center()
        {
            center(true, true);
        }
    
        private void center(bool horizontal, bool vertical)
        {
            Matrix m = new Matrix();
            m.Set(matrix);
            Drawable d = GetDrawable(Resource.Drawable.imageone);
            //Get image width and height
            int imgWidth = d.IntrinsicWidth;
            int imgHeight = d.IntrinsicHeight;
    
    
            RectF rect = new RectF(0, 0, imgWidth, imgHeight);
            m.MapRect(rect);
            float height = rect.Height();
            float width = rect.Width();
            float deltaX = 0, deltaY = 0;
    
            var metrics = Resources.DisplayMetrics;
    
            if (vertical)
            {
    
                int screenHeight = metrics.HeightPixels;
                //Phone screen resolution height
    
                if (height < screenHeight)
                {
                    deltaY = (screenHeight - height) / 2 - rect.Top;
                }
                else if (rect.Top > 0)
                {
                    deltaY = -rect.Top;
                }
                else if (rect.Bottom < screenHeight)
                {
                    deltaY = view.Height - rect.Bottom;
                }
            }
    
            if (horizontal)
            {
                //Phone screen resolution width
                int screenWidth = metrics.WidthPixels;
    
                if (width < screenWidth)
                {
                    deltaX = (screenWidth - width) / 2 - rect.Left;
                }
                else if (rect.Left > 0)
                {
                    deltaX = -rect.Left;
                }
                else if (rect.Right < screenWidth)
                {
                    deltaX = screenWidth - rect.Right;
                }
            }
            matrix.PostTranslate(deltaX, deltaY);
        }
    }
    

    The effect as follow :

    enter image description here