桌面程序的解锁方式一般是账号密码,互联网的可以使用扫码解锁,甚至人脸识别。但扫码需要网络,人脸识别又较复杂。所以就想把安卓常用的手势解锁移植到桌面程序上。

先来张效果图,有兴趣的往下看,没兴趣的打扰了。

WPF手势解锁使用鼠标点击事件,鼠标移动事件,鼠标弹起事件实现。自定义了三个属性(初始化颜色,选中颜色,选中点的集合),一个事件(绘制完成后触发的事件)。

实现的功能:

  绘制过程中直线随鼠标移动的效果

  绘制两个连接点的连线

  绘制完成后可调用的事件

  实现初始化颜色,选中颜色,选择连接点依赖属性

源码主要说明:

1.构造函数,完成事件注册

 /// <summary>
/// 构造函数
/// </summary>
public ScreenUnlock()
{
InitializeComponent();
Points = new List<int>();
this.Loaded += ScreenUnlock_Loaded;
this.MouseDown += ScreenUnlock_MouseDown;
this.MouseUp += ScreenUnlock_MouseUp;
this.MouseMove += ScreenUnlock_MouseMove;
}

2.窗体加载事件

绘制九宫格,tag用动态类型保存了实际位置(Point)和序号(Loaction)

 /// <summary>
/// Load事件,绘制九宫格
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScreenUnlock_Loaded(object sender, RoutedEventArgs e)
{
canvas.Children.Clear();
//为了保证正方形
var distance = Math.Min(this.ActualWidth == ? this.Width : this.ActualWidth, this.ActualHeight == ? this.Height : this.ActualHeight) / ;
double left = (distance - PointSize) / ;
for (var i = ; i < ; i++)
{
for (var j = ; j < ; j++)
{
var x = j * distance + left;
var y = i * distance + left;
Ellipse ellipse = new Ellipse()
{
Width = PointSize,
Height = PointSize,
Fill = Color,
Tag = new
{
Point = new Point(x + PointSize / , y + PointSize / ),
Location = i * + j +
}
};
ellipse.SetValue(Canvas.LeftProperty, x);
ellipse.SetValue(Canvas.TopProperty, y);
Canvas.SetLeft(ellipse, x);
Canvas.SetTop(ellipse, y);
canvas.Children.Add(ellipse);
}
}
}

3.鼠标左键点击事件

3.1清空了除九宫格之外所有元素

3.2判断点击位置是否是圆点位置,如果不是则不处理,否则记录当前位置用于画线,一条是跟踪鼠标的线(currentLine),另一个是为了显示选中的圆点的连线,此处记录绘制线的第一个点(currentEllipse与后续经过的点的连线).

 private void ScreenUnlock_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
//每次点击都是重新绘制,清空除了九宫格的所有元素
while (canvas.Children.Count > )
canvas.Children.RemoveAt(canvas.Children.Count - );
ellipseList.Clear();
currentEllipse = null;
Points.Clear(); //再次点击时需要先把颜色修改为初始化颜色
foreach (Shape item in canvas.Children)
item.Fill = Color; //获取当前鼠标位置
var point = e.GetPosition(this);
//鼠标所在位置是否有圆点
if (VisualTreeHelper.HitTest(this, point).VisualHit is Ellipse ellipse) //鼠标经过圆点
{
currentEllipse = ellipse;
ellipseList.Add(ellipse);
Points.Add((int)((dynamic)ellipse.Tag).Location);
var p = (Point)((dynamic)currentEllipse.Tag).Point;
currentLine = new Line()
{
Stroke = Color,
StrokeThickness = PointSize / ,
X1 = p.X,
Y1 = p.Y,
X2 = p.X,
Y2 = p.Y
};
}
}
}

4.鼠标移动事件

4.1绘制跟随鼠标的线

4.2判断是否经过之前没经过的圆点,绘线过程中,一个点只能用一次。经过的点保存在ellipseList集合中。

4.3如果经过未曾经过的点,则与上个经过的点绘制直线,并且重新赋值当前点currentEllipse,重新定义跟随鼠标的线(currentLine)的起始点为该点。

4.4把点添加到Points集合中

 /// <summary>
/// 鼠标移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScreenUnlock_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
//鼠标左键处于点击状态
if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
//获取当前鼠标位置
var point = e.GetPosition(this); ///当没有遇到圆点之前绘制跟随鼠标的线
if (currentLine != null)
{
canvas.Children.Remove(currentLine);
currentLine.X2 = point.X;
currentLine.Y2 = point.Y;
canvas.Children.Add(currentLine);
} //线跟着移动
if (VisualTreeHelper.HitTest(this, point).VisualHit is Ellipse ellipse && currentEllipse != null)
{
var p1 = (Point)((dynamic)currentEllipse.Tag).Point;
var p = (Point)((dynamic)ellipse.Tag).Point;
if (p1 != p) //鼠标经过圆点
{
//如果不包含该圆点,一个点只能用一次
if (!ellipseList.Contains(ellipse))
{
//绘制当前点和上个点之间的连线
var t = new Line()
{
Stroke = Color,
StrokeThickness = PointSize / ,
X1 = p1.X,
Y1 = p1.Y,
X2 = p.X,
Y2 = p.Y
};
//修改当前点
currentEllipse = ellipse;
ellipseList.Add(ellipse);
canvas.Children.Add(t);
Points.Add((int)((dynamic)ellipse.Tag).Location);
if (currentLine != null)
{
canvas.Children.Remove(currentLine);
currentLine.X1 = p.X;
currentLine.Y1 = p.Y;
currentLine.X2 = p.X;
currentLine.Y2 = p.Y;
canvas.Children.Add(currentLine);
}
}
}
}
}
}

5.鼠标左键弹起事件

5.1鼠标弹起时,修改所有经过的点以及点之间的连线颜色。

5.2清空所有使用的临时的变量,currentEllipse,currentLine

5.3触发绘制后触发的事件(AfterDraw)

 /// <summary>
/// 鼠标左键弹起
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScreenUnlock_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (canvas.Children.Count > )
foreach (Shape item in canvas.Children)
if (item is Line)
item.Stroke = SelectedColor;
else if (item is Ellipse ellipse && ellipseList.Contains(ellipse))
item.Fill = SelectedColor;
currentEllipse = null;
currentLine = null;
canvas.Children.Remove(currentLine);
RaiseEvent(new RoutedEventArgs(AfterDrawEvent));
}

6.选中点和线的颜色,SelectedColor属性

设置该颜色时,需要同时修改选中的点和线的颜色。

 /// <summary>
/// 选中的颜色
/// </summary>
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(SolidColorBrush), typeof(ScreenUnlock), new FrameworkPropertyMetadata(new SolidColorBrush(Colors.Green), new PropertyChangedCallback((s, e) =>
{
var t = s as ScreenUnlock;
if (t.canvas.Children.Count > )
for (int i = ; i < t.canvas.Children.Count; i++)
{
Shape item = t.canvas.Children[i] as Shape;
if (item is Line)
item.Stroke = e.NewValue as SolidColorBrush;
else if (item is Ellipse ellipse)
item.Fill = e.NewValue as SolidColorBrush;
}
}))); /// <summary>
/// 选中的颜色
/// </summary>
public SolidColorBrush SelectedColor
{
get { return GetValue(SelectedColorProperty) as SolidColorBrush; }
set { SetValue(SelectedColorProperty, value); }
}

7.绘制用的点的集合Points

绑定Points属性,后台就可以获取到绘制图案经历的点的集合。

8.其他代码

其他包含初始颜色,绘制完成以后触发的事件,以及使用到的变量。见源码。

9.利用该控件实现解锁

9.1绑定三个属性一个事件,分别是初始化颜色(Color),选中的颜色(SelectedColor),经过的点(Points)

9.2SelectedColor绑定方式

需要一个转换器(验证正确与否与颜色的转换),如果验证正确,则显示绿色,否则显示红色。

9.3如果连接的点太少时,则需进行提示,并且恢复原来的状态(即把选中的颜色设置为初始化的颜色)

参考:

https://www.cnblogs.com/ShenNan/p/5587009.html

源码:

没找到上传附件,附上码云地址。

https://gitee.com/yiyecao/temporary-components

WPF实现手势解锁的更多相关文章

  1. SJGestureUnlock快速集成手势解锁

    前言:如果页面显示不完整或图片看不了还请移步:简书 SJGestureUnlock.h 常用自定义属性 @interface SJGestureUnlock : UIView @property (n ...

  2. Quartz2D复习(二) --- 手势解锁

    这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了... 那么手势解锁功能是怎么是实现的呢,这里使用Quart2D来简单模拟一下, 先看下 ...

  3. HTML5实现屏幕手势解锁

    HTML5实现屏幕手势解锁(转载) https://github.com/lvming6816077/H5lockHow to use? <script type="text/java ...

  4. iOS--开发之手势解锁

    本文主要介绍通过手势识别实现手势解锁功能,这个方法被广泛用于手机解锁,密码验证,快捷支付等功能实现.事例效果如下所示. 首先,我们先分析功能的实现过程,首先我们需要先看大致的实现过程: 1.加载九宫格 ...

  5. 2016-1-10 手势解锁demo的实现

    一:实现自定义view,在.h,.m文件中代码如下: #import <UIKit/UIKit.h> @class ZLLockView; @protocol ZLLockViewDele ...

  6. iOS绘制手势解锁密码

    手势解锁这个功能其实已经用的越来越少了.但是郁闷不知道我公司为什么每次做一个app都要把手势解锁加上.....于是就自己研究了一下手势解锁页面的实现.. 要想实现这个页面,先说说需要掌握哪些: UIP ...

  7. [iOS UI进阶 - 5.0] 手势解锁Demo

    A.需求 1.九宫格手势解锁 2.使用了绘图和手势事件   code source: https://github.com/hellovoidworld/GestureUnlockDemo     B ...

  8. ReactNative手势解锁(react-native-ok-gesture-password)

    在大前端的趋势之下,我也慢慢开始从事React Native相关的开发.但是奈何React Native生态相对于Android来说还是太小了.许多开源的库早早就已经不再维护.之前项目中需要用到手势解 ...

  9. iOS-高仿支付宝手势解锁(九宫格)

    概述 高仿支付宝手势解锁, 通过手势枚举去实现手势密码相对应操作. 详细 代码下载:http://www.demodashi.com/demo/10706.html 基上篇[TouchID 指纹解锁] ...

随机推荐

  1. JS click延迟解决方案

    click延迟解决方案     移动端click事件会有300ms的延迟,原因是移动端屏幕双击会缩放页面 1.禁止缩放功能 浏览器禁用默认双击缩放行为去掉300ms的点击延迟 user-scalabl ...

  2. 来自灵魂的拷问——知道什么是SQL执行计划吗?

    面试官说:工作这么久了,应该知道sql执行计划吧,讲讲Sql的执行计划吧! 看了看面试官手臂上纹的大花臂和一串看不懂的韩文,吞了吞口水,暗示自己镇定点,整理了一下思绪缓缓的对面试官说:我不会 面试官: ...

  3. HourglassNet

  4. 商品描述(动画)--- jQuery

    本文章实现是基于jQuery展示商品描述的一个功能 (1)鼠标移入显示描述内容,鼠标移开内容隐藏.先来看看一个先后效果. (2)jQuery所以的文件可以自行下载,也可以在我主页找到文件,右键文件名复 ...

  5. Go之Gorm简介及使用案例

    简介 ORM Object-Relationl Mapping, 它的作用是映射数据库和对象之间的关系,方便我们在实现数据库操作的时候不用去写复杂的sql语句,把对数据库的操作上升到对于对象的操作 G ...

  6. [leetcode/lintcode 题解] Google面试题:合法组合

    给一个单词s,和一个字符串集合str.这个单词每次去掉一个字母,直到剩下最后一个字母.求验证是否存在一种删除的顺序,这个顺序下所有的单词都在str中.例如单词是’abc’,字符串集合是{‘a’,’ab ...

  7. C#算法设计查找篇之04-斐波那契查找

    斐波那契查找(Fibonacci Search) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/704 访问. 斐波那契 ...

  8. C#LeetCode刷题之#628-三个数的最大乘积( Maximum Product of Three Numbers)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3726 访问. 给定一个整型数组,在数组中找出由三个数组成的最大乘 ...

  9. go微服务系列(三) - 服务调用(http)

    1. 关于服务调用 2. 基本方式调用服务 3. 服务调用正确姿势(初步) 3.1 服务端代码 3.2 客户端调用(重要) 1. 关于服务调用 这里的服务调用,我们调用的可以是http api也可以是 ...

  10. STL函数库的应用第二弹——快排sort函数与结构体关键字排序

    时隔20多天,本蒟蒻终于记起了他的博客园密码!!! 废话不多说,今天主题:STL快排函数sort()与结构体关键字排序 Part 1:引入和导语 首先,我们需要知道,algorithm库里有一些奇怪的 ...