梦见你的名字 发表于 2024-6-15 02:09:30

鸿蒙系统的自定义手势暗码功能实现

简述:在最经开辟鸿蒙app的过程中,须要做一个手势暗码登录页面,固然鸿蒙官网上提供了相应的组件,但是并不能满足我们的业务需求,全部我们只能本身自定义控件。先来看看我本身自定义手势暗码页面的结果,大要满足了实际的业务需求。
先看下结果图
https://img-blog.csdnimg.cn/direct/4e1248ee0a93439b888058ee0a0bba5b.gif
具体的实现步骤如下:
1. 确定ui容器的选择
手势暗码一般都是九宫格的方式分列,很显着这里最优的选择容器是RelativeContainer
这个容器就相当于Android的RelativeLayout,用法也很相似,不清楚的朋侪可以自行去官网查看
用法,这里就不一一讲解了。
大致的结构模子图如下
https://img-blog.csdnimg.cn/direct/97257448575e4e6f8ccdb972c55c1546.png
一般情况下手势暗码都是9个点,但是不排除有二班的情况,为了防止设置的的4*4或者5*5的情况出现,以是我在结构的地方接纳了一种更灵活的方式,逻辑可能有些许绕,不过静下心来也是很轻易看懂的,直接上代码:

ForEach(this.ViewArr, (item: ChildViewModel, index: number) => {
GestureLockView({
    clickImage: this.clickImage,
    defaultImage: this.defaultImage,
    mGestureLockViewWidth: this.mGestureLockViewWidth,
    mMarginBetweenLockView: this.mMarginBetweenLockView,
    childViewModel: item

})
    .alignRules({
      top: {
      //如果是第一行,则以自身为基础,如果不是第一行,为在上一行元素的底部
      anchor: (index < this.mCount ? '__container__' : ('view_' + (index - this.mCount))),
      //如果是第一行则头部为VerticalAlign.Top,否则头部与前一行尾部对齐
      align: (index < this.mCount ? VerticalAlign.Top : VerticalAlign.Bottom)
      },
      //如果是第一列则为以自身为基础,如果不是,则以前一个元素为基础,在他的右侧
      left: {
      anchor: (index % this.mCount === 0 ? '__container__' : ('view_' + (index - 1))),
      //如果是第一列那么头对应HorizontalAlign.Start,否则头部就与前面一列的尾部对齐
      align: (index % this.mCount === 0 ? HorizontalAlign.Start : HorizontalAlign.End)
      }

    })
    .margin({
      left: this.mMarginBetweenLockView,
      top: this.mMarginBetweenLockView,
      right: this.mMarginBetweenLockView,
      bottom: this.mMarginBetweenLockView,
    })

    .id(item.viewId)
    .onAreaChange((oldValue: Area, newValue: Area) => {
      item.left = newValue.position.x?.valueOf() as number;
      item.top = newValue.position.y?.valueOf() as number;
      item.right = item.left + (newValue.width.valueOf() as number)
      item.bottom = item.top + (newValue.height.valueOf() as number)
      item.centX = ((item.left + item.right) / 2.0) + ""
      item.centY = ((item.top + item.bottom) / 2.0) + ""
    })

;

}) 表明也详细,这里就不讲解了
2.自定义画布和path组件的摆放
通过上面的步骤我们实现了手势暗码的结构,接下来我们须要实现手指与屏幕交互的功能(画连接线)。这里须要通过画布和path组件来实现来实现,首先我们需定义一个画布组件
Canvas(this.canvasContext)
.width(this.mWidth)
.height(this.mWidth)
.id("Canvas") 拿到画布组件后,须要将画布组件盖在RelativeContainer上,紧着这我们须要获取一个path组件,然后将path组件盖在画布组件上面
Line()
.startPoint()
.endPoint()
.strokeWidth(px2vp(5))
.stroke(this.lineColor)
.id("line") 这样我们全部的组件摆放动作就完成了。
3.实现手指与屏幕的交互
我们想要在屏幕上的画布上画线,我们必须要直到我们所画直线的起点坐标和终点坐标,鸿蒙系统给我们提供了组件的触摸事件,我们只须要从触摸事件的回调函数中获取手辅导击屏幕的坐标值,然后再将这两个值作为path的起点。
那么怎么实现两个按钮之间的连线呢?这就须要通过画布来实现了,这里我认识两个特别重要的api,一个是moveTo,一个是LineTo,这两个api和Android中path中的moveTo,pathTo寄义基本一样。moveTo(x,y)的意思是将路径的起点设置为这个函数的x,y中,我们须要画的路劲就须要这个x,y为起点,LineTo这个函数的意思是设计此path的终点,而且将此终点设置为下一段path的起点。认识了这两个重要的api,我们就可以接着就可以干活了
当手指触遇到第一个按钮的时候,记下按钮的圆心的坐标值,然后将它通过画布设置到moveTo(x,y)函数中,当手指滑动到第二手势暗码按钮时,我们再将第二个手势暗码的按钮的坐标传入到LineTo(x,y)中,这就完成了两个按钮之间的连线,当手指触遇到第三个按钮时,我们将第三个按钮的坐标的值设置到LineTo(x,y)中,这样就实现了第二个点和第三个点相连。以此类推,这样就实现了手势暗码之间各个按钮之间的连线。
固然这这只是实现了各个按钮之间的连线,我们常常利用手势暗码的时候,会看到一个引导线,也就是我们常常说的方向线。这个功能的实现我们须要用到Line组件了。
同样当手指触遇到第一个按钮的时候,记下按钮的圆心的坐标值,然后将此坐标值设置到Line组件的startPoint,当手指触碰的及时坐标传入到Line的endPoint中,这样就实现了引导线的功能。
还是直接上代码吧。
.onTouch((event: TouchEvent) => {
let x: number = ((event.touches.x) < 0 ? 0 : (event.touches.x))
x = (x > this.mWidth ? this.mWidth : x)
let y: number = ((event.touches.y) < 0 ? 0 : (event.touches.y))
y = (y > this.mWidth ? this.mWidth : y)
switch (event.type) {
//按下
    case TouchType.Down:
      this.reset();
      this.canvasContext.beginPath()
      this.canvasContext.lineWidth = px2vp(5)
      this.canvasContext.strokeStyle = this.lineColor
      break;
//移动
    case TouchType.Move:
    //获取当前的点击的ChildViewModel
      let childViewModel: ChildViewModel | undefined = this.getChildIdByPos(x, y, this.ViewArr)
      if (childViewModel != undefined) {
      let passWord: number = childViewModel.password;
      this.ViewArr.isClick = true;
      if (!this.passwordArr.includes(passWord)) {

          this.passwordArr.push(passWord)
          this.mLastPathX = childViewModel.left / 2 + childViewModel.right / 2;
          this.mLastPathY = childViewModel.top / 2 + childViewModel.bottom / 2;

          // 设置引线的起点坐标
          this.startPointX = this.mLastPathX;
          this.startPointY = this.mLastPathY;

          if (this.passwordArr.length == 1) // 当前添加为第一个
          {

            this.canvasContext.moveTo(this.mLastPathX, this.mLastPathY);
          } else
          // 非第一个,将两者使用线连上
          {
            this.canvasContext.lineTo(this.mLastPathX, this.mLastPathY);

            this.canvasContext.stroke()
          }
      }
      }
    //设置引导线的终点坐标
      this.endPointX = (this.startPointX == 0 ? 0 : x);
      this.endPointY = (this.startPointY == 0 ? 0 : y);
      break;
//抬起
    case TouchType.Up:
    //设置引导线的终点坐标
      this.endPointX = (this.startPointX == 0 ? 0 : this.mLastPathX);
      this.endPointY = (this.startPointY == 0 ? 0 : this.mLastPathY);

      if (this.passwordArr.length < this.minLength) {
      if (this.passwordArr.length > 0) {
          if (this.callBack != undefined) {
            this.callBack(ResultCode.fail, "至少连接" + this.minLength + "个点");
          }

      }
      this.reset();
      } else {
      let passWord: string = "";
      for (let passwordArrElement of this.passwordArr) {
          passWord += passwordArrElement;
      }
      if (this.callBack != undefined) {
          this.callBack(ResultCode.success, passWord);
      }

      }
      break;
} 至此自定义手势暗码控件的大要功能就实现了,如有错误欢迎各位大佬辅导
源码地址:myCode: 鸿蒙系统自定义手势暗码的实现

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 鸿蒙系统的自定义手势暗码功能实现