Xamarin.ios 手势密码

Posted Devin.Zhou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xamarin.ios 手势密码相关的知识,希望对你有一定的参考价值。

Xamarin.ios 手势密码

 

主要问题:

1. 图形绘制

  • 实心圆
  • 空心圆
  • 线段

2. Touch事件处理

  • TouchesBegan
  • TouchesMoved
  • TouchesEnded
  • TouchesCancelled

3. 各个圆坐标计算

4. 圆圈的选中逻辑

  • 判断点是否在圆内
  • 判断选中的两个圆心连线是否经过一个圆,如果是则该圆也是选中

 

 

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using CoreGraphics;
using Foundation;
using ObjCRuntime;
using UIKit;

namespace MyPassword.iOS.View.GuestureLock
{
    [Register("GuestureLockUIView")]
    public partial class GuestureLockUIView : UIView
    {

        private int Circle_R = 20;
        private int Distance = 40;
        private int Circle_r = 3;

        private int Length = 0;

        private double ViewWidth = 0;
        private double ViewHight = 0;
        private double MyPadding = 0;

        private int X_Zero = 0;
        private int Y_Zero = 0;
        

        CGContext cGContext;

        public GuestureLockUIView(IntPtr handle) : base(handle)
        {
            Initialize();
        }

        public GuestureLockUIView()
        {
            Initialize();
        }

        public GuestureLockUIView(RectangleF bounds) : base(bounds)
        {
            Initialize();
        }
        
        void Initialize()
        {
            BackgroundColor = UIColor.Green;
            
            Length = 3 * Circle_R * 2 + Distance * 2;
            ViewWidth = 320f;
            ViewHight = 320f;

            MyPadding = (ViewWidth - Length) / 2;
            X_Zero = (int)MyPadding + Circle_R;
            Y_Zero = (int)MyPadding + Circle_R;
            InitPointList();
        }



        private List<Vector2> pointList = new List<Vector2>();

        private List<Vector2> checkedList = new List<Vector2>();

        private List<Vector2> drawList = new List<Vector2>();

        private List<int> indexList = new List<int>();
        

        public delegate void CheckCompeleteDelegate(List<int> checkList);

        private CheckCompeleteDelegate _CheckCompeleteDelegate;

        public event CheckCompeleteDelegate CheckCompeleteEvent
        {
            add
            {
                _CheckCompeleteDelegate = Delegate.Combine(_CheckCompeleteDelegate, value) as CheckCompeleteDelegate;
            }
            remove
            {
                _CheckCompeleteDelegate = Delegate.Remove(_CheckCompeleteDelegate, value) as CheckCompeleteDelegate;
            }
        }


        private void GetCheckedIndex()
        {
            indexList.Clear();
            foreach (var item in checkedList)
            {
                int index = pointList.IndexOf(item);
                indexList.Add(index);
            }
        }
        

        public override void Draw(CGRect rect)
        {
            base.Draw(rect);

            cGContext = UIGraphics.GetCurrentContext();
            int size = pointList.Count;
           
            for (int i = 0; i < size; i++)//绘制元素点图
            {
                Vector2 item = pointList.ElementAt(i);

                cGContext.SetFillColor(UIColor.Blue.CGColor);
                cGContext.AddEllipseInRect(new CGRect(item.X - Circle_r, item.Y - Circle_r, Circle_r * 2, Circle_r * 2));
                cGContext.DrawPath(CGPathDrawingMode.Fill);

                cGContext.SetStrokeColor(UIColor.Blue.CGColor);
                cGContext.SetLineWidth(2);
                cGContext.AddEllipseInRect(new CGRect(item.X- Circle_R, item.Y- Circle_R, Circle_R * 2, Circle_R * 2));
                cGContext.DrawPath(CGPathDrawingMode.Stroke);
            }
            size = drawList.Count;
            for (int i = 0; i < size; i++)//绘制选中点图
            {
                Vector2 item = drawList.ElementAt(i);


                cGContext.SetFillColor(UIColor.Red.CGColor);
                cGContext.AddEllipseInRect(new CGRect(item.X- Circle_r, item.Y- Circle_r, Circle_r * 2, Circle_r * 2));
                cGContext.DrawPath(CGPathDrawingMode.Fill);
                if (i < size - 1)
                {
                    Vector2 item2 = drawList.ElementAt(i + 1);

                    cGContext.SetStrokeColor(UIColor.Red.CGColor);
                    cGContext.MoveTo(item.X,item.Y);
                    cGContext.AddLineToPoint(item2.X,item2.Y);
                    cGContext.DrawPath(CGPathDrawingMode.Stroke);

                    cGContext.SetStrokeColor(UIColor.Red.CGColor);
                    cGContext.SetLineWidth(2);
                    cGContext.AddEllipseInRect(new CGRect(item.X - Circle_R, item.Y- Circle_R, Circle_R * 2, Circle_R * 2));
                    cGContext.DrawPath(CGPathDrawingMode.Stroke);
                }
            }

        }


        public void Reset()
        {
            checkedList.Clear();
            drawList.Clear();
            SetNeedsDisplay();
        }


        private double touch_x = 0;
        private double touch_y = 0;

        public override void TouchesBegan(NSSet touches, UIEvent evt)
        {
            base.TouchesBegan(touches, evt);
            if (touches.AnyObject is UITouch touch)
            {
                touch_x = touch.LocationInView(this).X;
                touch_y = touch.LocationInView(this).Y;
                ProcessTouchEvent(touch_x, touch_y);
            }
        }

        public override void TouchesMoved(NSSet touches, UIEvent evt)
        {
            base.TouchesMoved(touches, evt);
            if (touches.AnyObject is UITouch touch)
            {
                touch_x= touch.LocationInView(this).X;
                touch_y= touch.LocationInView(this).Y;
                ProcessTouchEvent(touch_x, touch_y);
            }
        }

        public override void TouchesEnded(NSSet touches, UIEvent evt)
        {
            base.TouchesEnded(touches, evt);
            GetCheckedIndex();
            if (_CheckCompeleteDelegate != null)
            {
                _CheckCompeleteDelegate.Invoke(indexList);
            }
            Reset();
        }
        public override void TouchesCancelled(NSSet touches, UIEvent evt)
        {
            base.TouchesEnded(touches, evt);
            Reset();
        }

        private void ProcessTouchEvent(double x, double y)
        {
            //DebugUtil.WriteLine("x = "+x + "  y = "+y);
            if (x < 0 || y < 0 || x > ViewWidth || y > ViewHight)
            {

            }
            else
            {
                Vector2 item = CheckRange(x, y, out bool isIn);
                if (isIn && !IsAdded(item))
                {
                    if (checkedList.Count > 0)
                    {
                        var item2 = checkedList.Last();
                        foreach (Vector2 v in pointList)
                        {
                            if (item != v && !IsAdded(v) && CheckOnLine(item, item2, v))
                            {
                                checkedList.Add(v);
                            }
                        }
                    }
                    checkedList.Add(item);
                }
                else
                {
                    drawList.Clear();
                    drawList.AddRange(checkedList);
                    drawList.Add(item);
                }

                SetNeedsDisplay();
            }
        }



        /// <summary>
        /// 判断 v 是否在 v1、v2连线内  用了最粗暴的方法  
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        private bool CheckOnLine(Vector2 v1, Vector2 v2, Vector2 v)
        {
            double len = CalcLengthBetweenTwoPoint(v1, v2);
            double len1 = CalcLengthBetweenTwoPoint(v1, v);
            double len2 = CalcLengthBetweenTwoPoint(v2, v);
            return len == len1 + len2;
        }

        /// <summary>
        /// 计算v1、v2连线长度
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        private double CalcLengthBetweenTwoPoint(Vector2 v1, Vector2 v2)
        {
            double value = Math.Pow(v1.X - v2.X, 2.0) + Math.Pow(v1.Y - v2.Y, 2.0);
            //return value;
            return Math.Abs(Math.Sqrt(value));
        }

        /// <summary>
        /// 判断x、y 是否在其中一个圆内
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="isIn"></param>
        /// <returns></returns>
        private Vector2 CheckRange(double x, double y, out bool isIn)
        {
            foreach (Vector2 v in pointList)
            {
                if (IsInCircle(x, y, v) && !IsAdded(v))
                {
                    isIn = true;
                    return v;
                }
            }
            isIn = false;
            return new Vector2 { X = (int)x, Y = (int)y };

        }

        /// <summary>
        /// 判断x、y 是否在 v 为圆心 Circle_R 为半径的圆内
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        private bool IsInCircle(double x, double y, Vector2 v)
        {
            return Math.Pow(x - v.X, 2.0) + Math.Pow(y - v.Y, 2.0) <= Math.Pow(Circle_R, 2.0);
        }

        /// <summary>
        /// 判断item 是否已经选中
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private bool IsAdded(Vector2 item)
        {
            return checkedList.Contains(item);
        }

        /// <summary>
        /// 初始化 原始数据
        /// </summary>
        private void InitPointList()
        {
            int deta_x = 0;
            int deta_y = 0;
            int x = 0;
            int y = 0;
            for (int i = 0; i < 9; i++)
            {
                deta_x = i % 3;
                deta_y = i / 3;
                x = X_Zero + deta_x * (Distance + 2 * Circle_R);
                y = Y_Zero + deta_y * (Distance + 2 * Circle_R);
                
                pointList.Add(new Vector2
                {
                    X = x,
                    Y = y
                });

            }
        }

    }
    
    class Vector2
    {
        public int X { get; set; }
        public int Y { get; set; }
    }
}

 

以上是关于Xamarin.ios 手势密码的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin IOS UILabel在UIScrollView中点击手势不起作用

Xamarin iOS (9.2):手势在模拟器中不起作用

如何在 IO (Xamarin.IO) 中动态启用和滚动 UIScrollView?

java 使手势监听器在片段中可行

Xamarin.IOS。代码分析 - CA2123

xamarin.ios 使用仅图像代码实现 PageController