Xamarin.Android 手势密码

Xamarin.Android 手势密码

主要问题:

1. 图形绘制

  • 实心圆
  • 空心圆
  • 线段

2. Touch事件处理

  •  MotionEventActions.Down
  •  MotionEventActions.Move
  • MotionEventActions.Up

3. 各个圆坐标计算

4. 圆圈的选中逻辑

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

 

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 
  6 using Android.App;
  7 using Android.Content;
  8 using Android.Graphics;
  9 using Android.OS;
 10 using Android.Runtime;
 11 using Android.Util;
 12 using Android.Views;
 13 using Android.Widget;
 14 using static Android.Views.View;
 15 using MyPassword.Droid.Utils;
 16 using MyPassword.Utils;
 17 
 18 namespace MyPassword.Droid.Views
 19 {
 20     public class GestureLockView : View,IOnTouchListener
 21     {
 22 
 23 
 24         private  int Circle_R = 20;
 25         private  int Distance = 40;
 26         private  int Circle_r = 3;
 27 
 28         private int Length = 0;
 29 
 30         private double ViewWidth = 0;
 31         private double ViewHight = 0;
 32         private double MyPadding = 0;
 33 
 34         private int X_Zero = 0;
 35         private int Y_Zero = 0;
 36 
 37 
 38 
 39         private List<Vector2> pointList = new List<Vector2>();
 40 
 41         private List<Vector2> checkedList = new List<Vector2>();
 42 
 43         private List<Vector2> drawList = new List<Vector2>();
 44 
 45         private List<int> indexList = new List<int>();
 46 
 47         Paint paint;
 48 
 49         public delegate void CheckCompeleteDelegate(List<int> checkList);
 50 
 51         private CheckCompeleteDelegate _CheckCompeleteDelegate;
 52 
 53         public event CheckCompeleteDelegate CheckCompeleteEvent
 54         {
 55             add
 56             {
 57                 _CheckCompeleteDelegate = Delegate.Combine(_CheckCompeleteDelegate, value) as CheckCompeleteDelegate;
 58             }
 59             remove
 60             {
 61                 _CheckCompeleteDelegate = Delegate.Remove(_CheckCompeleteDelegate, value) as CheckCompeleteDelegate;
 62             }
 63         }
 64 
 65 
 66         private void GetCheckedIndex()
 67         {
 68             indexList.Clear();
 69             foreach (var item in checkedList)
 70             {
 71                 int index = pointList.IndexOf(item);
 72                 indexList.Add(index);
 73 
 74             }
 75         }
 76 
 77         public GestureLockView(Context context, IAttributeSet attrs) :
 78             base(context, attrs)
 79         {
 80             Initialize();
 81         }
 82 
 83         public GestureLockView(Context context, IAttributeSet attrs, int defStyle) :
 84             base(context, attrs, defStyle)
 85         {
 86             Initialize();
 87         }
 88 
 89         private void Initialize()
 90         {
 91             Circle_r = DensityUtil.Dp2px(Context,3f);
 92             Circle_R = DensityUtil.Dp2px(Context, 20f);
 93             Distance = DensityUtil.Dp2px(Context, 40f);
 94             Length = 3 * Circle_R * 2 + Distance * 2;
 95             ViewWidth = DensityUtil.Dp2px(Context, 320f);
 96             ViewHight = DensityUtil.Dp2px(Context, 320f);
 97 
 98             MyPadding = (ViewWidth - Length) / 2;
 99             X_Zero = (int)MyPadding + Circle_R;
100             Y_Zero = (int)MyPadding + Circle_R;
101             paint = new Paint();
102             SetOnTouchListener(this);
103             InitPointList();
104             PostInvalidate();
105         }
106 
107 
108 
109 
110         protected override void OnDraw(Canvas canvas)
111         {
112             base.OnDraw(canvas);
113 
114             int size = pointList.Count;
115             paint.StrokeWidth = 6;
116             paint.AntiAlias = true;
117             for (int i = 0; i < size; i++)//绘制元素点图
118             {
119                 Vector2 item = pointList.ElementAt(i);
120                 paint.Color = Color.Blue;
121                 paint.SetStyle(Paint.Style.Fill);//设置为实心
122                 canvas.DrawCircle(item.X, item.Y, Circle_r,paint);
123                 paint.SetStyle(Paint.Style.Stroke);//设置为空心
124                 canvas.DrawCircle(item.X, item.Y, Circle_R, paint);
125             }
126             size = drawList.Count;
127             for (int i = 0; i < size; i++)//绘制选中点图
128             {
129                 Vector2 item = drawList.ElementAt(i);
130                 paint.Color = Color.Red;
131                 paint.SetStyle(Paint.Style.Fill);//设置为实心
132                 canvas.DrawCircle(item.X, item.Y, Circle_r, paint);
133                 if (i < size - 1)
134                 {
135                     Vector2 item2 = drawList.ElementAt(i + 1);
136                     paint.Color = Color.Red;
137                     canvas.DrawLine(item.X, item.Y, item2.X, item2.Y, paint);
138                     paint.SetStyle(Paint.Style.Stroke);//设置为空心
139                     canvas.DrawCircle(item.X, item.Y, Circle_R, paint);
140                 }
141             }
142 
143         }
144 
145 
146         public void Reset()
147         {
148             checkedList.Clear();
149             drawList.Clear();
150             PostInvalidate();
151         }
152 
153 
154         private double touch_x = 0;
155         private double touch_y = 0;
156 
157         public bool OnTouch(View v, MotionEvent e)
158         {
159             switch (e.Action)
160             {
161                 case MotionEventActions.Down:
162                 case MotionEventActions.Move:
163                     touch_x = e.GetX();
164                     touch_y = e.GetY();
165                     ProcessTouchEvent(touch_x, touch_y);
166                     break;
167                 case MotionEventActions.Up:
168                     GetCheckedIndex();
169                     if (_CheckCompeleteDelegate != null)
170                     {
171                         _CheckCompeleteDelegate.Invoke(indexList);
172                     }
173                     Reset();
174                     break;
175             }
176             return true;
177         }
178 
179 
180         private void ProcessTouchEvent(double x, double y)
181         {
182             if (x < 0 || y < 0 || x > ViewWidth || y > ViewHight)
183             {
184 
185             }
186             else
187             {
188                 Vector2 item = CheckRange(x, y, out bool isIn);
189                 if (isIn && !IsAdded(item))
190                 {
191                     if (checkedList.Count > 0)
192                     {
193                         var item2 = checkedList.Last();
194                         foreach (Vector2 v in pointList)
195                         {
196                             if (item != v && !IsAdded(v) && CheckOnLine(item, item2, v))
197                             {
198                                 checkedList.Add(v);
199                             }
200                         }
201                     }
202                     checkedList.Add(item);
203                 }
204                 else
205                 {
206                     drawList.Clear();
207                     drawList.AddRange(checkedList);
208                     drawList.Add(item);
209                 }
210                 PostInvalidate();
211             }
212         }
213 
214 
215 
216         /// <summary>
217         /// 判断 v 是否在 v1、v2连线内  用了最粗暴的方法  
218         /// </summary>
219         /// <param name="v1"></param>
220         /// <param name="v2"></param>
221         /// <param name="v"></param>
222         /// <returns></returns>
223         private bool CheckOnLine(Vector2 v1, Vector2 v2, Vector2 v)
224         {
225             double len = CalcLengthBetweenTwoPoint(v1, v2);
226             double len1 = CalcLengthBetweenTwoPoint(v1, v);
227             double len2 = CalcLengthBetweenTwoPoint(v2, v);
228             return len == len1 + len2;
229         }
230 
231         /// <summary>
232         /// 计算v1、v2连线长度
233         /// </summary>
234         /// <param name="v1"></param>
235         /// <param name="v2"></param>
236         /// <returns></returns>
237         private double CalcLengthBetweenTwoPoint(Vector2 v1, Vector2 v2)
238         {
239             double value = Math.Pow(v1.X - v2.X, 2.0) + Math.Pow(v1.Y - v2.Y, 2.0);
240 
241             return Math.Abs(Math.Sqrt(value));
242         }
243 
244         /// <summary>
245         /// 判断x、y 是否在其中一个圆内
246         /// </summary>
247         /// <param name="x"></param>
248         /// <param name="y"></param>
249         /// <param name="isIn"></param>
250         /// <returns></returns>
251         private Vector2 CheckRange(double x, double y, out bool isIn)
252         {
253             foreach (Vector2 v in pointList)
254             {
255                 if (IsInCircle(x, y, v) && !IsAdded(v))
256                 {
257                     isIn = true;
258                     return v;
259                 }
260             }
261             isIn = false;
262             return new Vector2 { X = (int)x, Y = (int)y };
263 
264         }
265 
266         /// <summary>
267         /// 判断x、y 是否在 v 为圆心 Circle_R 为半径的圆内
268         /// </summary>
269         /// <param name="x"></param>
270         /// <param name="y"></param>
271         /// <param name="v"></param>
272         /// <returns></returns>
273         private bool IsInCircle(double x, double y, Vector2 v)
274         {
275             return Math.Pow(x - v.X, 2.0) + Math.Pow(y - v.Y, 2.0) <= Math.Pow(Circle_R, 2.0);
276         }
277 
278         /// <summary>
279         /// 判断item 是否已经选中
280         /// </summary>
281         /// <param name="item"></param>
282         /// <returns></returns>
283         private bool IsAdded(Vector2 item)
284         {
285             return checkedList.Contains(item);
286         }
287 
288         /// <summary>
289         /// 初始化 原始数据
290         /// </summary>
291         private void InitPointList()
292         {
293             //DebugUtil.WriteLine("Distance   == "+ Distance);
294             int deta_x = 0;
295             int deta_y = 0;
296             int x = 0;
297             int y = 0;
298             for (int i = 0; i < 9; i++)
299             {
300                 deta_x = i % 3;
301                 deta_y = i / 3;
302                 x = X_Zero + deta_x * (Distance + 2 * Circle_R);
303                 y = Y_Zero + deta_y * (Distance + 2 * Circle_R);
304 
305 
306                 pointList.Add(new Vector2
307                 {
308                     X = x,
309                     Y = y
310                 });
311 
312             }
313         }
314 
315     }
316 
317     class Vector2 {
318         public int X { get; set; }
319         public int Y { get; set; }
320     }
321 
322 }
View Code

 

posted @ 2017-12-18 13:56  Devin.Zhou  阅读(503)  评论(0编辑  收藏  举报