#2023盲盒+码# 使用ArkTS+Grid布局实现抽奖功能 原创

westinyang
发布于 2023-9-10 23:12
浏览
0收藏

【本文正在参加 2023「盲盒」+码有奖征文活动】 https://ost.51cto.com/posts/25284

@toc

序言

使用ArkTS+Grid布局实现抽奖功能,效果如下

#2023盲盒+码# 使用ArkTS+Grid布局实现抽奖功能-开源基础软件社区

数据定义

// 礼物数据
@State numbers: number[] = [1, 2, 3, 8, 0, 4, 7, 6, 5]
gifts_images: Resource[] = [$r('app.media.1'), $r('app.media.2'), $r('app.media.3'), $r('app.media.4'), $r('app.media.5'), $r('app.media.6'), $r('app.media.7'), $r('app.media.8')]
gifts_hints: string[] = ['玫瑰花', '项链', '戒指', '手表', '护肤品', '口红', '华为Mete60', '红包']
// 礼物索引
@State idx: number = 0
// 抽奖进行进行中标记
@State running: boolean = false
// 当前步数
@State currentStep: number = 0
// 随机步数
@State randomSteps: number = 0
// 随机减速步数
@State randomDecelerationSteps: number = 0
// 速度
@State speed: number = 100
// 抽奖结果
@State resultIndex: number = -1

布局实现

  • Grid实现9宫格布局,中间的格子点击时触发开始抽奖
  • 根据当前索引设定礼物格子的背景色,实现转动效果
  • 抽奖结果索引记录在 resultIndex,从 gifts_hints 中拿到礼物名称并显示
build() {
  Column({ space: 5 }) {
    // 标题栏
    Text('节日礼物').height(65).fontSize(28).fontWeight(FontWeight.Bold)

    // 抽奖区
    Grid() {
      ForEach(this.numbers, (val: number) => {
        GridItem() {
          Stack() {
            if (val != 0) {
              Image(this.gifts_images[val-1])
            } else {
              Text('开始')
                .fontSize(24)
                .width('100%')
                .height('100%')
                .textAlign(TextAlign.Center)
            }
          }
          .backgroundColor(this.getBGColor(val))
          .padding(3)
        }.onClick(()=>{
          if (val != 0) {
            return
          }
          if (this.running) {
            promptAction.showToast({message: '正在抽取中...', duration: 1000})
            return
          }
          this.start()
        })
      }, day => day)
    }
    .columnsTemplate('1fr 1fr 1fr')
    .rowsTemplate('1fr 1fr 1fr')
    .columnsGap(10)
    .rowsGap(10)
    .width('90%')
    .backgroundColor(0xFFFFFF)
    .height(320)

    // 普通提示区
    Text('还在纠结节日送什么礼物吗?\n\n来抽一个吧,绝对没有空哒~')
      .margin({top:20})
      .fontSize(22)

    // 中奖提示区
    Text('抽到了:' + this.gifts_hints[this.resultIndex] + (this.resultIndex == 7 ? ',快去发吧~' : ',快去买吧~'))
      .fontColor('#ff0000')
      .margin({top:20})
      .fontSize(22)
      .visibility(this.running || this.resultIndex == -1 ? Visibility.Hidden : Visibility.Visible)
  }.width('100%').margin({ top: 5 })
}

// 获取格子背景色
getBGColor(val: number) {
  if (val == 0) {
    return '#dddddd'
  }
  if (val == this.idx) {
    return '#ff0000'
  }
  return '#eeeeee'
}

逻辑控制

  • 礼物索引到8时重置为1,模拟转动效果
  • 速度默认100毫秒,剩余步数在随机减速步数范围内的时候,速度调整到300毫秒
// 开始抽取
start() {
  // 重置索引和启动标记
  this.idx = 0
  this.running = true
  // 随机步数
  this.randomSteps = this.getRandom(16, 32)
  // 随机减速步数
  this.randomDecelerationSteps = this.getRandom(3, 5)
  this.loop()
}

loop() {
  // 停止和重置
  if (this.currentStep >= this.randomSteps) {
    this.running = false
    this.resultIndex = this.idx - 1
    this.currentStep = 0
    this.randomSteps = 0
    this.randomDecelerationSteps = 0
    this.speed = 100
    return
  }
  // 步数递增和控制索引重置
  this.currentStep++
  if (this.idx == 8) {
    this.idx = 1
  } else {
    this.idx++
  }
  // 步数是否在减速范围内
  if (this.randomSteps - this.currentStep <= this.randomDecelerationSteps) {
    this.speed = 300
  }
  setTimeout(()=>{
    this.loop()
  }, this.speed)
}

// 获取随机数
getRandom(start, end, fixed = 0) {
  let differ = end - start
  let random = Math.random()
  return (start + differ * random).toFixed(fixed)
}

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
2
收藏
回复
举报
回复
    相关推荐