鸿蒙滑动拼图验证组件,有点意思...
bigegpt 2024-10-12 06:29 3 浏览
基于安卓平台的滑动拼图验证组件 SwipeCaptcha(https://github.com/mcxtzhang/SwipeCaptcha),实现了其核心功能的鸿蒙化迁移和重构,代码已经开源到,欢迎各位下载使用并提出宝贵意见!
开源地址:
https://gitee.com/isrc_ohos/SwipeCaptcha
在页面登录或者注册的时候,为了确保不是机器人操作,会让用户手动验证。验证方式分为滑动拼图验证和滑动验证两种。
本文的 SwipeCaptcha 组件可以实现滑动拼图的验证方式,操作简单,安全性强,被众多 APP 使用。
01组件效果展示
鸿蒙系统的 SwipeCaptcha 组件在使用时,有两个较为重要的图片:滑块和原图。
这两张图片被放置与同一水平线上,用户拖动滑块至原图处,误差在一定范围内,即可验证成功。
每次调用 SwipeCaptcha 组件,滑块和原图的位置都会发生随机变化,登录时被暴力破解的难度增加,安全性较高。
在 SwipeCaptcha 组件的验证界面,还有当前进度值和验证状态的描述。当前进度值表示滑块在水平方向的滑动进度,进度为 100 时,表示滑块滑至最右端。
进度值下方展示的是当前的验证状态,可分为:“开始”、“验证失败,请重新验证三种状态”、“验证成功”。
下面依次展示 SwipeCaptcha 组件拼图验证失败和成功的效果图。
①验证失败效果
用户未将滑块拖至原图处,导致滑块与原图的位置误差较大,验证失败。
②验证成功效果
用户拖动滑块至原图处,误差在一定范围内,验证成功。
02Sample 解析
Sample 主要包含以下四个部分:
- 拼图背景导入手机
- 裁剪滑块
- 绘制滑块
- 验证拼图是否成功
下面将通过具体步骤对上述四个部分进行详解。
①数据初始化
本步骤包含三个部分的数据设置:
- 获取手机屏幕宽度信息。
- 设置进度值和验证状态的初始提示文字,如“当前进度值”、“请滑动滑块验证”。
- 初始化画笔信息,定义画笔属性。
//获取手机屏幕宽度displayAttributes.width
DisplayManager displayManager = DisplayManager.getInstance();
Display display = displayManager.getDefaultDisplay(this).get();
DisplayAttributes displayAttributes = display.getAttributes();
windowWidth = displayAttributes.width;
// 进度值初始化
text = new Text(this);
text.setMarginTop(800);// 距离顶端边界的距离
text.setText("当前进度值"+ progress);// 设定文字
text.setTextSize(100);// 设定字号
myLayout.addComponent(text);// 添加进布局中
// 验证状态初始化
text2 = new Text(this);
text2.setMarginTop(1000);
text2.setText("请滑动滑块验证");
text2.setTextSize(100);
myLayout.addComponent(text2);
//初始化画笔的信息
mPaint = new Paint();
mPaint.setColor(Color.BLACK);//定义颜色
mPaint.setAntiAlias(true);//定义虚实线
mPaint.setStrokeWidth(5f);//定义宽度
mPaint.setStyle(Paint.Style.STROKE_STYLE);//定义绘图方式
②背景图片绘制
用手机屏幕的宽度除以背景图片的宽度,得到背景图片的缩放比例,当该图片显示在手机中,按照此比例缩放可与屏幕同宽。
该比例用于背景图片适配不同型号的手机屏幕。
//背景图片的缩放比例
float ratio = (float) windowWidth/(float) img.getImageInfo().size.width;
//背景图片绘制
Component image = new Component(this);
Component.DrawTask drawTask = new Component.DrawTask() {
@Override
public void onDraw(Component component, Canvas canvas) {
//按照比例进行缩放
canvas.scale(ratio , ratio);
//绘图
canvas.drawPixelMapHolder(pixelMapHolder, 0, 0, new Paint());
}
};
image.addDrawTask(drawTask);
myLayout.addComponent(image);
③确定滑块和原图的位置
puzzleWidth 为滑块或者原图的宽度;top 为随机数值,表示滑块或者原图的上边距离背景图片上边的距离;puzzel2left 也为随机数值,表示原图左边距离背景图片左边的距离。
有了以上三个变量可以确定组件中滑块和原图的初始位置和大小(滑块初始时位于屏幕的最左侧)。
下面介绍上述属性是如何计算出来的:
//puzzleWidth 为屏幕宽度的1/6
puzzleWidth = windowWidth/6;
//top为图片缩放后高度与抠图高度之差再乘以随机数
top = (float) Math.random()*(img.getImageInfo().size.height*ratio - puzzleWidth);
//原图位置一定在滑块位置右面
//屏幕宽度减去两个拼图宽度 *随机数,后向右平移一个滑块的长度
puzzel2left = ((windowWidth -puzzleWidth*2) * (float)Math.random()) + puzzleWidth;
④获取滑块
本步骤需要根据原图的位置,解码出一个图片作为滑块。
首先设置滑块的形状为矩形,依据上述的 puzzel2left、puzzleWidth 属性,确定矩形所在区域,依据缩放比例,将矩形区域映射为原比例图像,并对此图像进行解码,得到滑块图像数据。
PixelMap puzzlePixelMap =
getPuzzlePixelMap(this , ResourceTable.Media_longa , new Rect((int)(puzzel2left/ratio), (int) (top/ratio), (int) (puzzleWidth/ratio) , (int) (puzzleWidth/ratio)));
PixelMapHolder pixelMapHolder1 = new PixelMapHolder(puzzlePixelMap);
⑤绘制滑块
滑块通过画笔来绘制,其位置应该根据滑动进度条的进度来移动,并且要对不同手机屏幕的进行适配。
同时,为了和用户友好的交互,我们还需要为滑块绘制一个边框,告知用户这个边框所在就是滑块(原图也需要绘制边框,原理相同)。
绘制滑块和边框的代码如下:
//绘制滑块
Component.DrawTask puzzelDrawTask = new Component.DrawTask() {
@Override
public void onDraw(Component component, Canvas canvas) {
Paint paint = new Paint();
//移动小滑块拼图
canvas.translate(slider.getProgress()*displayAttributes.width /100 , top);
//进行适当比例缩放
canvas.scale(ratio , ratio);
canvas.drawPixelMapHolder(pixelMapHolder1 , 0 , 0 , paint);
}
};
//绘制滑块边框
Component puzzleFrame = new Component(this);
Component.DrawTask drawTask2 = new Component.DrawTask() {
@Override
public void onDraw(Component component, Canvas canvas) {
//方框左侧位置
float left = slider.getProgress()*windowWidth /100;
//绘制边框的左边
canvas.drawLine(new Point(left , top),
new Point(left, top + puzzleWidth), mPaint);
//绘制边框的上边
canvas.drawLine(new Point(left, top),
new Point(left + puzzleWidth, top), mPaint);
//绘制边框的右边
canvas.drawLine(new Point(left + puzzleWidth, top),
new Point(left + puzzleWidth, top + puzzleWidth), mPaint);
//绘制边框的下边
canvas.drawLine(new Point(left, top + puzzleWidth),
new Point(left + puzzleWidth, top + puzzleWidth), mPaint);
}
};
⑥进度条滑动更新
为进度条设置监听,拖动进度条会引起三处更新:
- 滑块位置和滑块边框位置的更新
- 进度值的更新
- 验证状态的更新
在验证状态的更新中,需要对用户拖动进度条结束时的验证状态进行判断,滑块和原图的位置差距是否在误差范围内,如果在范围内,则显示验证成功,如果不在误差范围内,则显示验证失败,提示需要重新验证。
//设置进度条监听
slider.setValueChangedListener(new Slider.ValueChangedListener() {
@Override
//拖动进度条引起的更新
public void onProgressUpdated(Slider slider, int i, boolean b) {
//滑块的位置更新
puzzle.invalidate();
//滑块边框位置的更新
puzzleFrame.invalidate();
//进度值更新
text.setText("当前进度值 : " + slider.getProgress());
}
}
//当用户开始滑动进度条时,验证状态变为“开始”字样。
public void onTouchStart(Slider slider) {
//开始拖动的方法
text2.setText("开始");
}
//判断滑块左侧边的位置和原图的左侧边的位置是否在误差内
public void onTouchEnd(Slider slider) {
if(((slider.getProgress()*windowWidth /100)<(puzzel2left + puzzleWidth/10))&&((slider.getProgress()*windowWidth /100)>(puzzel2left - puzzleWidth/10)))
{
text2.setText("验证成功");
}else {
text2.setText("验证失败,请重新验证");
slider.setProgressValue(10);
}
}
项目贡献人:赵柏屹、郑森文、朱伟、陈美汝、张馨心
作者: 朱伟ISRC
文章链接:https://mp.weixin.qq.com/s/sVeRfcEtD4T9MRftkDm8KQ
相关推荐
- Redis集群对比:主从复制、哨兵模式、Cluster一文看懂所有优缺点
-
在分布式系统中,Redis作为高性能的内存数据库,其集群方案的选择直接影响到系统的稳定性、可用性和扩展性。本文将全面对比Redis的三种主流集群方案:主从复制、哨兵模式和Cluster模式,帮助开发者...
- redis的主从复制,读写分离,主从切换
-
当数据量变得庞大的时候,读写分离还是很有必要的。同时避免一个redis服务宕机,导致应用宕机的情况,我们启用sentinel(哨兵)服务,实现主从切换的功能。redis提供了一个master,多个sl...
- # Redis 入门到精通(九)-- 主从复制(3)
-
#Redis入门到精通(九)--主从复制(3)##一、redis主从复制-常见问题(1)###1、伴随着redis系统的运行,master的数据量会越来越大,一旦master重启...
- redis - 主从复制(Redis主从复制时序图)
-
1引言在上一篇文章中,我们了解了Redis两种不同的持久化方式,Redis服务器通过持久化,把Redis内存中持久化到硬盘当中,当Redis宕机时,我们重启Redis服务器时,可以由RDB文件或AO...
- # Redis 入门到精通(九)-- 主从复制(2)
-
#Redis入门到精通(九)--主从复制(2)##一、redis主从复制--数据同步阶段注意事项###1、数据同步阶段master说明1)如果master数据量巨大,数据同步阶段应...
- Redis主从复制(redis主从复制主节点挂了)
-
介绍Redis有两种不同的持久化方式,Redis服务器通过持久化,把Redis内存中持久化到硬盘当中,当Redis宕机时,我们重启Redis服务器时,可以由RDB文件或AOF文件恢复内存中的数据。不过...
- 深入解析 Redis 集群的主从复制实现方式
-
在互联网大厂的后端开发领域,Redis作为一款高性能的内存数据库,被广泛应用于缓存、消息队列等场景。而Redis集群中的主从复制机制,更是保障数据安全、实现读写分离以及提升系统性能的关键所在。今...
- Redis主从架构详解(redis主从架构高可用如何实现)
-
Redis主从架构搭建Redis主节点配置创建主节点目录(/opt/redis-master),复制redis.conf到该目录下,redis.conf配置项修改#后台启动daemonizeyes...
- 抖音“四大包塘战神”:承包了全网的快乐
-
在抖音钓鱼垂类领域,"包塘战神"军团正掀起一场黑色幽默风暴。空军华、大表坑、李赔光、透心良四位创作者,以承包鱼塘为舞台,用连续翻车的钓鱼直播构筑起流量奇观。当钓鱼佬在抖音集体转型喜剧人...
- ORACLE 11G RAC 安装-通过VM配置共享磁盘
-
简介:在自己的电脑上通过VM软件搭建Oracle11GRAC,通过修改VM的参数文件来实现磁盘共享!目标:搭建RAC环境实现:使用VMwareWorkstation8.0.0+ORACLE...
- Linux操作系统安全配置(linux系统安全配置包括)
-
一、服务相关命令systemctlenable服务名#开机自启动systemctldisable服务名#禁用开机自启动systemctlstop服务名#停止服务systemctls...
- 关于Linux性能调优中网络I/O的一些笔记
-
写在前面和小伙伴分享一些Linux网络优化的笔记,内容很浅,可以用作入门博文内容结合《Linux性能优化》读书笔记整理涉及内容包括常用的优化工具(mii-tool,ethtool,ifconfig,i...
- 从 Sonatype Nexus Repository Manager 迁移到 Artifactory
-
1.Nexus1.1下载下载链接:https://help.sonatype.com/repomanager3/product-information/download/download-archiv...
- Ubuntu20安装zabbix5.0企业监控系统亲测教程
-
前言示例主机:zabbix10.0.100.10,将安装在UbuntuServer上教程说明:因使用官方教程无法安装成功,所以本教程与官方教程有所不同安装前提:已安装UbuntuServer2...
- Linux内核设计与实现—进程管理(linux内核程序设计)
-
进程进程就是处于执行期的程序(目标码存放在某种存储介质上)。进并不仅仅局限于一段可执行程序代码(Unix称其为代码段,textsection)。通常进程还要包含其他资源,像打开的文件,挂起的信号,...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- linux安装minio (74)
- ubuntuunzip (67)
- vscode使用技巧 (83)
- secure-file-priv (67)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)