文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

OpenHarmony - 基于 ArkUI(JS)实现图案解锁组件(一)

2024-12-01 15:24

关注

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

前言

Openharmony作为我们国内开源系统,并且以js/ets最为开发语言,完全抛弃了java。作为一名前端开发人员,也需要为咱们国产系统壮大起来,所以贡献一份微薄之力。

项目介绍

ohos-pattern是一个解锁功能的组件,是基于openharmony AkrUI(JS)实现的。在手机指纹解锁还没来临之前,图案解锁是一个很热门的功能,包括数字解锁。不过现在也还很多应用场景中有使用到图案解锁和数字解锁的功能。本文图案解锁仅仅只是实现UI层面,并不涉及到加密解密的的方式。这个可以二次开发使用。

本文为第一篇,后续会更新加入数字解锁功能,如果后续能涉及到生物识别API,还会加入指纹解锁等三种解锁方式。

环境说明

效果展示

组件属性

属性名

类型

默认值

作用

radius

Number

5

密码点半径[5-20]

scope

Number

20

热区范围[20-40]

point-color

String

#383838

密码点内颜色

point-stroke-color

String

#ff9800

密码点边框颜色

active-color

String

#ff9800

激活密码点颜色

line-color

String

#1a73e8

密码线颜色

active-line-color

String

#04be02

激活密码线颜色

is-show-line

Boolean

true

是否显示密码线

组件事件

属性名

类型

返回值

备注

result-cb

Function

Array

返回密码结果

引用组件

<element name="ohos-pattern" src="../../common/component/ohosPattern/ohosPattern">element>
<div class="container">
<ohos-pattern
radius="{{radius}}"
scope="{{scope}}"
point-color="{{pointColor}}"
point-stroke-color="{{pointStrokeColor}}"
active-color="{{activeColor}}"
line-color="{{lineColor}}"
active-line-color="{{activeLineColor}}"
is-show-line="{{isShowLine}}"
>ohos-pattern>
div>

实现思路

实现思路比较简单,使用canvas绘制九个密码点,然后通过监听手势触摸和9个密码点的碰撞产生密码数据

  1. 创建canvas。
  2. 绘制9个密码点。
  3. 绘制可控区域(就是密码点跟随手指一动区域)。
  4. 监听手势。

实现过程

1、创建canvas

创建canvas元素,并且绑定touchstart,touchmove,touchend手势事件。

<div class="container">
<canvas
id="canvas"
ref="canvas"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
style="width: {{w}}px;height: {{h}}px"
>canvas>
div>

在js中初始化canvas对象。

onShow(){
this.initCanvas();
},
// 初始化画布
initCanvas(){
const c = this.$refs.canvas;
this.ctx = c.getContext('2d', { antialias: true });
},

2、绘制九个密码点

下面看个草图:

从草图上可以看出我们的密码点位置了,这里使用for循环方法实现,创建3行,每行3个点。

这里有个注意点,因为我们密码点有一个需要跟随手势移动的需求,需要修改point_list的数据,所以使用point_list_copy复制了一份出来,这里使用es6的展开运算符…来实现深拷贝。

// 创建9个密码点
createPoint(){
let point_x = Math.ceil((this.w - this.R * 6) / 4 + this.R);
let point_y = Math.ceil((this.h - this.R * 6) / 4 + this.R);
for (var j = 0; j < 3; j++) {
for (var i = 0; i < 3; i++) {
let d = {
x: point_x * (i + 1) + this.R * i,
y: point_y * (j + 1) + this.R * j
}
this.point_list.push(d);
this.point_list_copy = [...this.point_list];
this.drawPoint(d);
}
}
},

下面实现将9个密码点到画布上。

// 绘制9个密码点到画布上
drawPoint(obj) {
let {x, y} = obj;
// 绘制外圆环
this.ctx.beginPath();
this.ctx.lineCap = "round"; //向线条的每个末端添加圆形线帽
this.ctx.lineWidth = (this.R / 2); //绘制圆的边框
this.ctx.strokeStyle = '#ff9800'; //绘制边框的颜色
this.ctx.arc(x, y, this.R, 0, 2 * Math.PI);
this.ctx.stroke();
this.ctx.closePath();

// 绘制内圆
this.ctx.beginPath();
this.ctx.arc(x, y, this.R, 0, 2 * Math.PI);
this.ctx.fillStyle = "#383838";
this.ctx.fill();
this.ctx.closePath();
},

下面来看看绘制后的效果:

3、监听手势和密码点的碰撞

我们写了三个手势事件

onTouchStart(e){
let x = e.touches[0].localX;
let y = e.touches[0].localY;
this.isCollision(x, y)
},
onTouchMove(e){
let x = e.touches[0].localX;
let y = e.touches[0].localY;
this.isCollision(x, y);
// 每次触摸后都需要清除画布重新绘制
this.ctx.clearRect(0, 0, this.w, this.h);
this.reDraw(x, y, true);
},
onTouchEnd(e){
this.ctx.clearRect(0, 0, this.w, this.h);
this.reDraw(e.touches[0].clientX, e.touches[0].clientY, false);
// 松开手后,记录所有触摸的点
lg.log('图案结果:',this.result)
this.result = [];
},

重绘画布:

// 重绘
reDraw(x, y, bol) {
for (let i in this.point_list) {
// 重新绘制9个密码点
this.drawPoint(this.point_list[i]);
}
for (let i in this.result) {
// 重新绘制密码状态
this.drawStatus(this.result[i]);
}

},

监听手势触摸是否和密码点发生碰撞。

this.scope表示热区范围,当触摸点进入这个热区范围,说明已经跟该密码点发生接触碰撞了。

// 是否跟9个密码点发生接触。
isCollision(x, y) {
let c_x, c_y;
for (let i in this.point_list) {
c_x = Math.abs(x - this.point_list[i].x);
c_y = Math.abs(y - this.point_list[i].y);
// 如果发生碰撞,记录状态
if (c_x < this.scope && c_y < this.scope) {
lg.warn('发生了碰撞,碰撞点是:', i)
this.drawStatus(i)
return
}
}
},

当触摸点和密码点发生碰撞之后,需要给该密码点绘制触摸状态

//  绘制触摸到密码点的状态
drawStatus(index) {
// 绘制状态内圆
this.ctx.beginPath();
this.ctx.arc(this.point_list[index].x, this.point_list[index].y, (this.R / 2), 0, 2 * Math.PI);
this.ctx.fillStyle = "#ac2dfb";
this.ctx.fill();
this.ctx.closePath();

//记录缓存碰撞的结果
if(this.result.indexOf(index) === -1){
this.result.push(index)
}
},

下面看看效果:

但是这样还不够,我们能还需要绘制连接的密码线。

4、绘制密码线

在重绘方法里最顶端加入绘制密码线方法。

this.drawLine(this.result, x, y, bol);

绘制密码线方法。

这里需要绘制两条线:

drawLine(arr, x, y, bol) {
if(arr.length === 0){
return;
}
// 当存在已经两个点的时候,两点直线形成连线
this.ctx.beginPath();
for (let i in arr) {
if (i == 0) {
this.ctx.moveTo(this.point_list[arr[i]].x, this.point_list[arr[i]].y);
} else {
this.ctx.lineTo(this.point_list[arr[i]].x, this.point_list[arr[i]].y);
}
}
this.ctx.strokeStyle = '#1a73e8';
this.ctx.lineWidth = (this.R / 2);
this.ctx.stroke();

// 跟着手机滑动的线条
if (bol) {
this.ctx.beginPath();
this.ctx.moveTo(this.point_list[arr[arr.length - 1]].x, this.point_list[arr[arr.length - 1]].y);
this.ctx.lineTo(x, y);
this.ctx.strokeStyle = '#04be02';
this.ctx.lineWidth = (this.R / 2);
this.ctx.stroke();
}
},

好了,下面我们看看加上密码线的效果:

5、实现可移动的密码点

优化体验,增加了密码点跟随手势一起移动的效果。

在重绘的顶部添加绘制可移动的密码点方法。

// 绘制跟随手势移动的密码点
this.pointAn(x,y,bol);

r_x,r_y表示密码点热区范围,在热区范围内可以将该密码点变为触摸点跟随触摸点一起移动,当触摸点离开了热区之后,密码点回到原来的中心位置。

// 绘制状态point范围内活动
pointAn(x, y, bol){
if(bol){
if(this.result.length === 0){
return;
}
let t = this.result[this.result.length - 1];
let r_x = Math.abs(x - this.point_list_copy[t].x);
let r_y = Math.abs(y - this.point_list_copy[t].y);
if(r_x < this.scope && r_y < this.scope){
this.point_list[t] = {x,y}
} else {
this.point_list = [...this.point_list_copy];
}
} else {
this.point_list = [...this.point_list_copy];
}
},

最后来看看加上热区的效果:

到这里,整个基本功能已经实现了。

最后再来看一下最终效果:

代码地址

​ohos-pattern 基于OpenHarmony JSAPI实现图案解锁组件​​。

总结

该组件整体实现逻辑都比较简单,主要是通过手势去绘制canvas画布实现的,这里需要注意的是,api version需要7以上,因为在api version 6 之前,存在canvas重绘闪屏的情况,在api 7之后修复了这个问题。相比api 6之前的版本,api8真的优化和修复了很多功能。很期待harmongOS 3.0更新,可以在真机下去体验ets开发的应用。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

来源:​​51CTO开源基础软件社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯