系列:鸿蒙 HarmonyOS 6.1 新特性实战 · 第 42 篇

QRCode 和 PatternLock 是 ArkUI 面向安全与分享场景的两个专用组件。QRCode 可将任意字符串实时渲染为二维码图像,PatternLock 则提供九宫格手势密码交互,常用于应用锁、支付验证等场景。本篇演示如何组合使用这两个组件,并实现颜色切换与密码设置完整流程。

运行效果

初始状态(QRCode 展示 + PatternLock 待绘制): 初始状态

切换颜色后的 QR 码与完成手势绘制: 交互后

QRCode 二维码生成

QRCode 组件接收任意字符串作为内容参数,自动编码并渲染为标准二维码。内容可以是 URL、纯文本、JSON 字符串等任意格式。

@State qrContent: string = 'https://developer.huawei.com'
@State qrColor: string = '#000000'
@State qrBgColor: string = '#ffffff'

QRCode(this.qrContent)
  .width(200)
  .height(200)
  .color(this.qrColor)
  .backgroundColor(this.qrBgColor)

.color() 控制前景色(码点颜色),背景色建议保持白色以确保扫码兼容性。动态修改 qrContent 绑定的状态变量即可实时更新二维码内容。

颜色切换示例:

private colorOptions: string[] = ['#000000', '#0066ff', '#e74c3c', '#27ae60']
@State selectedColor: number = 0

Row({ space: 12 }) {
  ForEach(this.colorOptions, (color: string, index: number) => {
    Column()
      .width(28)
      .height(28)
      .borderRadius(14)
      .backgroundColor(color)
      .border({
        width: this.selectedColor === index ? 3 : 1,
        color: this.selectedColor === index ? '#0066ff' : '#dddddd'
      })
      .onClick(() => {
        this.selectedColor = index
        this.qrColor = color
      })
  })
}

PatternLock 手势密码

PatternLock 渲染九宫格圆点,用户滑动连线设置或验证手势密码。通过 PatternLockController 控制器可以在代码中重置绘制状态。

private patternController: PatternLockController = new PatternLockController()
@State patternResult: string = ''
@State savedPattern: number[] = []
@State isConfirmStep: boolean = false
@State firstInput: number[] = []

PatternLock(this.patternController)
  .sideLength(240)
  .circleRadius(10)
  .pathColor('#0066ff')
  .onPatternComplete((input: number[]) => {
    this.handlePatternComplete(input)
  })
  • sideLength:九宫格整体边长(px),决定组件大小
  • circleRadius:每个圆点的半径
  • pathColor:连线颜色
  • onPatternComplete:绘制完成后触发,input 为经过的圆点序号数组(1-9,左上至右下排列)

两步密码设置流程

实际场景中,密码设置需要两次确认。以下实现“首次输入 → 确认输入“的完整流程:

handlePatternComplete(input: number[]): void {
  if (input.length < 4) {
    this.patternResult = '图案太短,至少连接 4 个点'
    this.patternController.reset()
    return
  }

  if (!this.isConfirmStep) {
    // 第一步:记录初始图案
    this.firstInput = input
    this.isConfirmStep = true
    this.patternResult = '请再次绘制确认图案'
    this.patternController.reset()
  } else {
    // 第二步:比对两次输入
    const match = this.firstInput.length === input.length &&
      this.firstInput.every((v: number, i: number) => v === input[i])

    if (match) {
      this.savedPattern = input
      this.patternResult = `密码设置成功!路径:${input.join('-')}`
    } else {
      this.patternResult = '两次图案不一致,请重新设置'
      this.firstInput = []
      this.isConfirmStep = false
    }
    this.patternController.reset()
  }
}

重置按钮:

Button('重新设置')
  .fontSize(14)
  .onClick(() => {
    this.isConfirmStep = false
    this.firstInput = []
    this.savedPattern = []
    this.patternResult = ''
    this.patternController.reset()
  })

完整代码

@Entry
@Component
struct QRCodePatternPage {
  @State qrContent: string = 'https://developer.huawei.com'
  @State qrColor: string = '#000000'
  @State selectedColor: number = 0
  @State patternResult: string = '请绘制手势密码(至少 4 个点)'
  @State savedPattern: number[] = []
  @State isConfirmStep: boolean = false
  @State firstInput: number[] = []

  private patternController: PatternLockController = new PatternLockController()
  private colorOptions: string[] = ['#000000', '#0066ff', '#e74c3c', '#27ae60']

  handlePatternComplete(input: number[]): void {
    if (input.length < 4) {
      this.patternResult = '图案太短,至少连接 4 个点'
      this.patternController.reset()
      return
    }
    if (!this.isConfirmStep) {
      this.firstInput = input
      this.isConfirmStep = true
      this.patternResult = '请再次绘制确认图案'
      this.patternController.reset()
    } else {
      const match = this.firstInput.length === input.length &&
        this.firstInput.every((v: number, i: number) => v === input[i])
      if (match) {
        this.savedPattern = input
        this.patternResult = `密码设置成功!路径:${input.join('-')}`
      } else {
        this.patternResult = '两次图案不一致,请重新设置'
        this.firstInput = []
        this.isConfirmStep = false
      }
      this.patternController.reset()
    }
  }

  build() {
    Scroll() {
      Column({ space: 24 }) {
        Text('二维码生成').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#333333')

        // 内容输入
        TextInput({ text: this.qrContent, placeholder: '输入二维码内容' })
          .width('100%')
          .fontSize(13)
          .onChange((val: string) => { this.qrContent = val })

        // 颜色选择
        Row({ space: 12 }) {
          Text('前景色:').fontSize(13).fontColor('#666666')
          ForEach(this.colorOptions, (color: string, index: number) => {
            Column()
              .width(28).height(28).borderRadius(14)
              .backgroundColor(color)
              .border({
                width: this.selectedColor === index ? 3 : 1,
                color: this.selectedColor === index ? '#0066ff' : '#dddddd'
              })
              .onClick(() => {
                this.selectedColor = index
                this.qrColor = color
              })
          })
        }

        // 二维码展示
        QRCode(this.qrContent)
          .width(200).height(200)
          .color(this.qrColor)
          .backgroundColor('#ffffff')

        Divider().strokeWidth(1).color('#eeeeee')

        // 手势密码
        Text('手势密码设置').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#333333')

        Text(this.isConfirmStep ? '第二步:确认图案' : '第一步:绘制图案')
          .fontSize(12).fontColor('#999999')

        Text(this.patternResult)
          .fontSize(14)
          .fontColor(this.savedPattern.length > 0 ? '#27ae60' : '#e74c3c')
          .textAlign(TextAlign.Center)

        PatternLock(this.patternController)
          .sideLength(240)
          .circleRadius(10)
          .pathColor('#0066ff')
          .onPatternComplete((input: number[]) => {
            this.handlePatternComplete(input)
          })

        Button('重新设置')
          .fontSize(14)
          .backgroundColor('#f5f5f5')
          .fontColor('#333333')
          .onClick(() => {
            this.isConfirmStep = false
            this.firstInput = []
            this.savedPattern = []
            this.patternResult = '请绘制手势密码(至少 4 个点)'
            this.patternController.reset()
          })
      }
      .width('100%')
      .padding(24)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#f8f8f8')
  }
}

API 速查

属性/方法 说明
QRCode(content) 传入字符串内容,自动生成二维码
.color(color) 二维码前景色(码点颜色)
.backgroundColor(color) 二维码背景色,建议保持白色
PatternLock(controller) 创建九宫格手势密码,绑定控制器
.sideLength(px) 九宫格整体边长(像素)
.circleRadius(px) 圆点半径
.pathColor(color) 连线颜色
.onPatternComplete(fn) 绘制完成回调,参数为圆点序号数组(1-9)
PatternLockController.reset() 清除当前绘制,恢复初始状态
Array.every(fn) 检查所有元素是否满足条件,用于路径比对

小结

  • QRCode 内容可以是任意字符串;前景色可自定义,但背景色建议保持白色以确保主流扫码 App 兼容
  • 修改绑定的 @State 变量后,QRCode 会自动重新渲染,无需手动刷新
  • PatternLock 圆点编号 1-9,从左上角到右下角依次排列,与手机拨号键盘布局一致
  • 最短路径建议设为 4 个点,安全性与易用性较为均衡
  • patternController.reset() 在每次 onPatternComplete 回调结束后调用,清除绘制痕迹
  • 两步密码设置流程中,使用 Array.every() 逐位比对路径数组是最简洁的方式

上一篇:Search 搜索框实战 | 下一篇:Marquee 跑马灯与 Gauge 仪表盘

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐