翻译自java示例https://raw.githubusercontent.com/Xjasz/AndroidZoomableViewGroup/master/ZoomListView.java
using Android.App; using Android.Widget; using Android.OS; using Android.Views; using System.Collections.Generic; using Android.Net; using Android.Graphics; using System.Net; using Android.Content; using Android.Util; using Java.Lang; namespace App1 { [Activity(Label = "App1", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView (Resource.Layout.Main); var listView1 = FindViewById<ListView>(Resource.Id.listView1); var rows = new List<RowItem>(); rows.Add(new RowItem { URL = "http://192.168.0.50:8001/OMS/tempimage/c152fd1f-ef44-42a6-96fb-3b4894ab8004636499813730162442.gif" }); rows.Add(new RowItem { URL = "http://192.168.0.50:8001/OMS/tempimage/9e8a1d81-7211-4c1f-bc5c-b7193c12a92c636499813730162442.gif" }); rows.Add(new RowItem { URL = "http://192.168.0.50:8001/OMS/tempimage/6f0eca83-7b5e-4e9e-999c-3ef88e277117636499813730162442.gif" }); listView1.Adapter = new ListViewRowAdapter(this, rows); } } public class MyListView : ListView { private MyListViewParameter ParameterInfo = new MyListViewParameter(); private ScaleGestureDetector ScaleDetector { get; set; } public MyListView(Context context) :base(context) { this.ScaleDetector = new ScaleGestureDetector(context, new ScaleListener(ParameterInfo, this)); } public MyListView(Context context, IAttributeSet attrs) :base(context,attrs) { this.ScaleDetector = new ScaleGestureDetector(context, new ScaleListener(ParameterInfo, this)); } public MyListView(Context context, IAttributeSet attrs, int defStyleAttr) :base(context,attrs,defStyleAttr) { this.ScaleDetector = new ScaleGestureDetector(context, new ScaleListener(ParameterInfo, this)); } public MyListView(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) :base(context,attrs,defStyleAttr,defStyleRes) { this.ScaleDetector = new ScaleGestureDetector(context, new ScaleListener(ParameterInfo, this)); } protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) { this.ParameterInfo.Width = MeasureSpec.GetSize(widthMeasureSpec); this.ParameterInfo.Height = MeasureSpec.GetSize(heightMeasureSpec); base.OnMeasure(widthMeasureSpec, heightMeasureSpec); } public override bool OnTouchEvent(MotionEvent ev) { var result = base.OnTouchEvent(ev); var action = ev.Action; this.ScaleDetector.OnTouchEvent(ev); switch (action) { case MotionEventActions.Down: { float x = ev.GetX(); float y = ev.GetY(); this.ParameterInfo.LastTouchX = x; this.ParameterInfo.LastTouchY = y; this.ParameterInfo.ActivePointerId = ev.GetPointerId(0); break; } case MotionEventActions.Move: { int pointerIndex = ev.FindPointerIndex(this.ParameterInfo.ActivePointerId); float x = ev.GetX(pointerIndex); float y = ev.GetY(pointerIndex); float dx = x - this.ParameterInfo.LastTouchX; float dy = y - this.ParameterInfo.LastTouchY; this.ParameterInfo.PosX += dx; this.ParameterInfo.PosY += dy; if (this.ParameterInfo.PosX > 0.0f) this.ParameterInfo.PosX = 0.0f; else if (this.ParameterInfo.PosX < this.ParameterInfo.MaxWidth) this.ParameterInfo.PosX = this.ParameterInfo.MaxWidth; if (this.ParameterInfo.PosY > 0.0f) this.ParameterInfo.PosY = 0.0f; else if (this.ParameterInfo.PosY < this.ParameterInfo.MaxHeight) this.ParameterInfo.PosY = this.ParameterInfo.MaxHeight; this.ParameterInfo.LastTouchX = x; this.ParameterInfo.LastTouchY = y; this.Invalidate(); break; } case MotionEventActions.Up: { this.ParameterInfo.ActivePointerId = this.ParameterInfo.INVALID_POINTER_ID; break; } case MotionEventActions.Cancel: { this.ParameterInfo.ActivePointerId = this.ParameterInfo.INVALID_POINTER_ID; break; } case MotionEventActions.PointerUp: { int pointerIndex = ((int)action & (int)MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift; int pointerId = ev.GetPointerId(pointerIndex); if (pointerId == this.ParameterInfo.ActivePointerId) { int newPointerIndex = pointerIndex == 0 ? 1 : 0; this.ParameterInfo.LastTouchX = ev.GetX(newPointerIndex); this.ParameterInfo.LastTouchY = ev.GetY(newPointerIndex); this.ParameterInfo.ActivePointerId = ev.GetPointerId(newPointerIndex); } break; } } return true; } protected override void OnDraw(Canvas canvas) { base.OnDraw(canvas); canvas.Save(SaveFlags.Matrix); canvas.Translate(this.ParameterInfo.PosX, this.ParameterInfo.PosY); canvas.Scale(this.ParameterInfo.ScaleFactor, this.ParameterInfo.ScaleFactor); canvas.Restore(); } protected override void DispatchDraw(Canvas canvas) { canvas.Save(SaveFlags.Matrix); if (this.ParameterInfo.ScaleFactor == 1.0f) { this.ParameterInfo.PosX = 0.0f; this.ParameterInfo.PosY = 0.0f; } canvas.Translate(this.ParameterInfo.PosX, this.ParameterInfo.PosY); canvas.Scale(this.ParameterInfo.ScaleFactor, this.ParameterInfo.ScaleFactor); base.DispatchDraw(canvas); canvas.Restore(); this.Invalidate(); } public class MyListViewParameter { public MyListViewParameter() { this.INVALID_POINTER_ID = -1; this.ActivePointerId = -1; this.ScaleFactor = 1.0f; this.MaxWidth = 0.0f; this.MaxHeight = 0.0f; } public int INVALID_POINTER_ID { get; private set; } public int ActivePointerId { get; set; } public float ScaleFactor { get; set; } public float MaxWidth { get; set; } public float MaxHeight { get; set; } public float LastTouchX { get; set; } public float LastTouchY { get; set; } public float PosX { get; set; } public float PosY { get; set; } public float Width { get; set; } public float Height { get; set; } } private class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener { private MyListViewParameter ParameterInfo { get; set; } private ListView MyListView { get; set; } public ScaleListener(MyListViewParameter pi,ListView lv) { this.ParameterInfo = pi; this.MyListView = lv; } public override bool OnScale(ScaleGestureDetector detector) { this.ParameterInfo.ScaleFactor *= detector.ScaleFactor; this.ParameterInfo.ScaleFactor = Math.Max(1.0f, Math.Min(this.ParameterInfo.ScaleFactor, 3.0f)); this.ParameterInfo.MaxWidth = this.ParameterInfo.Width - (this.ParameterInfo.Width * this.ParameterInfo.ScaleFactor); this.ParameterInfo.MaxHeight = this.ParameterInfo.Height - (this.ParameterInfo.Height * this.ParameterInfo.ScaleFactor); this.MyListView.Invalidate(); return true; } } } public class RowItem { public string URL { get; set; } } public class ListViewRowAdapter : BaseAdapter<RowItem> { List<RowItem> items; Activity context; public ListViewRowAdapter(Activity context, List<RowItem> items) : base() { this.context = context; this.items = items; } public override long GetItemId(int position) { return position; } public override RowItem this[int position] { get { return items[position]; } } public override int Count { get { return items.Count; } } /// <summary> /// 下载图片 /// </summary> /// <param name="url"></param> /// <returns></returns> private Bitmap GetImageBitmapFromUrl(string url) { Bitmap imageBitmap = null; using (var webClient = new WebClient()) { var imageBytes = webClient.DownloadData(url); if (imageBytes != null && imageBytes.Length > 0) { imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length); } } return imageBitmap; } public override View GetView(int position, View convertView, ViewGroup parent) { var item = items[position]; View view = convertView; if (view == null) // no view to re-use, create new view = context.LayoutInflater.Inflate(Resource.Layout.ListViewRow, null); var url = Uri.Parse(item.URL); view.FindViewById<ImageView>(Resource.Id.Image1).SetImageBitmap(GetImageBitmapFromUrl(item.URL)); return view; } } }