В Xamarin Android вы можете настроить Touch событие ImageView для его реализации.
Xml: добавление ImageView с примером изображения:
<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>
Затем в Активность вы можете настроить сенсорное событие:
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);
}
}
Эффект следующим образом: