xamarin C# 安卓实现 ListView 放大缩小

翻译自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;
        }
    }
}
复制代码

 

posted on   空明流光  阅读(550)  评论(0编辑  收藏  举报

编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2015-01-11 Updatepanel 注册javascript 方法
2015-01-11 Updatepanel 注册javascript 方法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示