WPF实现手势解锁
桌面程序的解锁方式一般是账号密码,互联网的可以使用扫码解锁,甚至人脸识别。但扫码需要网络,人脸识别又较复杂。所以就想把安卓常用的手势解锁移植到桌面程序上。
先来张效果图,有兴趣的往下看,没兴趣的打扰了。

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实现手势解锁的更多相关文章
- SJGestureUnlock快速集成手势解锁
前言:如果页面显示不完整或图片看不了还请移步:简书 SJGestureUnlock.h 常用自定义属性 @interface SJGestureUnlock : UIView @property (n ...
- Quartz2D复习(二) --- 手势解锁
这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了... 那么手势解锁功能是怎么是实现的呢,这里使用Quart2D来简单模拟一下, 先看下 ...
- HTML5实现屏幕手势解锁
HTML5实现屏幕手势解锁(转载) https://github.com/lvming6816077/H5lockHow to use? <script type="text/java ...
- iOS--开发之手势解锁
本文主要介绍通过手势识别实现手势解锁功能,这个方法被广泛用于手机解锁,密码验证,快捷支付等功能实现.事例效果如下所示. 首先,我们先分析功能的实现过程,首先我们需要先看大致的实现过程: 1.加载九宫格 ...
- 2016-1-10 手势解锁demo的实现
一:实现自定义view,在.h,.m文件中代码如下: #import <UIKit/UIKit.h> @class ZLLockView; @protocol ZLLockViewDele ...
- iOS绘制手势解锁密码
手势解锁这个功能其实已经用的越来越少了.但是郁闷不知道我公司为什么每次做一个app都要把手势解锁加上.....于是就自己研究了一下手势解锁页面的实现.. 要想实现这个页面,先说说需要掌握哪些: UIP ...
- [iOS UI进阶 - 5.0] 手势解锁Demo
A.需求 1.九宫格手势解锁 2.使用了绘图和手势事件 code source: https://github.com/hellovoidworld/GestureUnlockDemo B ...
- ReactNative手势解锁(react-native-ok-gesture-password)
在大前端的趋势之下,我也慢慢开始从事React Native相关的开发.但是奈何React Native生态相对于Android来说还是太小了.许多开源的库早早就已经不再维护.之前项目中需要用到手势解 ...
- iOS-高仿支付宝手势解锁(九宫格)
概述 高仿支付宝手势解锁, 通过手势枚举去实现手势密码相对应操作. 详细 代码下载:http://www.demodashi.com/demo/10706.html 基上篇[TouchID 指纹解锁] ...
随机推荐
- Java 多态 接口继承等学习笔记
Super关键字 1.子类可以调用父类声明的构造方法 : 语法:在子类的构造方法中使用super关键字 super(参数列表) 2.操作被隐藏的成员变量(子类的成员变量和父类的成员变量重名的说法)和 ...
- 「MoreThanJava」Day 5:面向对象进阶——继承详解
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- XCTF-WEB-高手进阶区-Web_python_template_injection-笔记
Web_python_template_injection o(╥﹏╥)o从这里开始题目就变得有点诡谲了 网上搜索相关教程的确是一知半解,大概参考了如下和最后的WP: http://shaobaoba ...
- 关于手机数码圈KOL的一两点感想
复工以来,高峰时段9号线地铁上的人依旧不少,安全距离啥的肯定是不用想了,只是从原来的4G手机换成5G手机以后在某些站能接收到5G信号,我终于能在一些原来根本没信号的站里愉快的刷一刷微博和酷安了. 但是 ...
- Vue组件通信之父传子
一般情况下,子组件中无法直接使用父组件的变量.借助子组件的props选项可以实现这一点. 这里我将一个vue实例作为一个父组件: const app = new Vue({ el:'#div1', d ...
- 【Linux】zookeeper-3.5.6启动失败8080端口被占用
通过查看zookeeper的官方文档 1. 可以禁用adminServer 2.可以删除jetty服务
- ALGEBRA-2 有限维向量空间
关键词:张成.线性无关.基.维度 linear span: V中任意一组向量的span都是V的子空间(对加法和数乘封闭) linear independent 线性无关 https://www.zy ...
- Visual Studio Code中设置sftp同步代码到服务器
## **前言** - 绝对的大佬才会直接在Linux下用vim写代码,我等小白只能通过IDE来了,所以将代码同步到服务器上就很重要了.使用vs code设置好sftp就可以实现这一功能. - 设置之 ...
- C#LeetCode刷题之#34-在排序数组中查找元素的第一个和最后一个位置(Find First and Last Position of Element in Sorted Array)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4970 访问. 给定一个按照升序排列的整数数组 nums,和一个目 ...
- Spring Boot 教程 - MyBatis-Plus
1. Mybatis-Plus简介 MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生. 为什么说Myba ...