【06】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-综合案例·生肖抽奖卡具体实现(类似支付宝集五福)

序言:

本文综合了前五次笔记的知识内容,完成了相对来说较为复杂的生肖抽奖卡案例,通过拆分和一步步的思路分析完成本案例,通过完成这次案例,笔者可以说是把前面的所有内容或多或少的都有所复习,特此分享给大家。

笔者也是跟着B站黑马的课程一步步学习,学习的过程中添加部分自己的想法整理为笔记分享出来,如有代码错误或笔误,欢迎指正。

B站黑马的课程链接:鸿蒙课程介绍_哔哩哔哩_bilibili

 往期笔记:

【01】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-ArkTs基础语法与界面开发基础

【02】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-界面进阶与布局排布(附QQ登陆、得物、京东登陆综合案例+代码)

【03】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-更多布局(弹性/层叠)方式与界面开发综合(附飞狗卡片+B站卡片案例+实战开发支付宝界面+代码)

【04】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-ArkTs进阶运算符+状态管理(附综合案例美团购物车)

【05】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-条件渲染+if/switch判断与for/while循环(附计数器、京东加购案例) 

目录

综合案例-生肖抽奖卡

一.初始布局:

二.初始界面

三.抽卡遮罩层

四.随机效果

五.抽大奖遮罩层

最终代码


综合案例-生肖抽奖卡

一.初始布局:

1.Badge 角标组件

角标用我们前文提到过的绝对定位也一样可以实现,不过这种角标太常用了,故有内置的badge角标组件。

语法:

    Badge({
      count:1,//角标数值
      position:BadgePosition.RightTop,//角标位置
      style:{
        fontSize:12,//文字大小
        badgeSize:16,//圆形大小
        badgeColor:'#FA2A2D'//圆形颜色
      }
    })

代码示意:

2.Grid 布局

对于这种规规整整的布局方式,我们可以用以前学过的Column或者Row,也可以用Grid布局方式。

横向:columnTemplate

纵向:RowTemplate

代码示意:

@Entry
@Component
struct Index {
  build() {
    Grid(){
      ForEach([1,2,3,4,5,6,7,8,9,10,11,12],()=>{
        GridItem(){
          Column(){


          }
          .width(80)
          .height(80)
          .backgroundColor(Color.Pink)
          .border({
            width:2
          })
        }
      })
    }
    .columnsTemplate('1fr 1fr 1fr')
    .rowsTemplate('1fr 1fr 1fr 1fr')
    .width('100%')
    .height(500)
    .backgroundColor(Color.Blue)
  }
}

二.初始界面

1.初始界面阶段01-静态布局(代码略):

2.初始界面阶段02-数据动态渲染:

每个列表项→两个数据

①图片的地址

②抽中的数量

代码示意:

//1.定义接口(每个列表项的数据结构)
interface ImageCount{
  url:string
  count:number
}


@Entry
@Component
struct Index {
  @State images:ImageCount[]=[
    {url:'app.media.bg_00',count:0},
    {url:'app.media.bg_01',count:1},
    {url:'app.media.bg_02',count:2},
    {url:'app.media.bg_03',count:3},
    {url:'app.media.bg_04',count:4},
    {url:'app.media.bg_05',count:5}
  ]
  build() {
    Column(){


      Grid(){
        ForEach(this.images,(item:ImageCount,index:number)=>{
          GridItem(){
            Badge({
              count:item.count,
              position:BadgePosition.RightTop,
              style:{
                fontSize:14,
                badgeSize:20,
                badgeColor:'#fa2a2d'
              }
            }){
              Image($r(item.url))
                .width(70)
            }
          }
        })
      }
      .columnsTemplate('1fr 1fr 1fr')
      .rowsTemplate('1fr 1fr')
      .width('100%')
      .height(300)


      Button('立即抽卡')
        .width(200)
        .backgroundColor('#1d5b8c')
        .margin({top:50})
    }


  }
}

三.抽卡遮罩层

1.思路分析:

①布局角度:层叠布局Stack

②结构角度:Column>Text+Image+Button

代码示意:

      //抽卡遮罩层
      Column({space:30}){
        Text('获得生肖卡')
          .fontColor('#f5ebcf')
          .fontSize(30)
          .fontWeight(700)
        Image($r('app.media.img_01'))
          .width(200)
        Button('开心收下')
          .width(200)
          .height(50)
          .backgroundColor(Color.Transparent)
          .border({width:2,color:'#fff9e0'})
      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
      .backgroundColor('#cc000000')

2.显隐效果控制

需求1:点击抽卡,才显示遮罩层

需求2:图片,要有缩放显示动画

遮罩层显隐控制:

①透明度opacity:0 → 1

②层级zIndex:-1 → 99

图片动画:

缩放scale:0 → 1

代码示意:

//定义接口(每个列表项的数据结构)
interface ImageCount{
  url:string
  count:number
}
//需求1:点击抽卡,才显示遮罩层
//需求2:图片,要有缩放显示动画


@Entry
@Component
struct Index {
  @State images:ImageCount[]=[
    {url:'app.media.bg_00',count:0},
    {url:'app.media.bg_01',count:1},
    {url:'app.media.bg_02',count:2},
    {url:'app.media.bg_03',count:3},
    {url:'app.media.bg_04',count:4},
    {url:'app.media.bg_05',count:5}
  ]
  //控制遮罩层显隐
  @State maskOpacity:number = 0
  @State maskzIndex:number = -1
  //控制图片动画缩放
  @State maskImageX:number = 0
  @State maskImageY:number = 0
  build() {
    Stack(){
      //初始化布局结构
      Column(){


        Grid(){
          ForEach(this.images,(item:ImageCount,index:number)=>{
            GridItem(){
              Badge({
                count:item.count,
                position:BadgePosition.RightTop,
                style:{
                  fontSize:14,
                  badgeSize:20,
                  badgeColor:'#fa2a2d'
                }
              }){
                Image($r(item.url))
                  .width(70)
              }
            }
          })
        }
        .columnsTemplate('1fr 1fr 1fr')
        .rowsTemplate('1fr 1fr')
        .width('100%')
        .height(300)


        Button('立即抽卡')
          //点击时修改遮罩参数
          .onClick(()=>{
            this.maskOpacity=1
            this.maskzIndex=99
            this.maskImageX=1
            this.maskImageY=1
          })
          .width(200)
          .backgroundColor('#1d5b8c')
          .margin({top:50})




      }
      .width('100%')
      .height('100%')
      .backgroundColor(Color.Pink)


      //抽卡遮罩层
      Column({space:30}){
        Text('获得生肖卡')
          .fontColor('#f5ebcf')
          .fontSize(30)
          .fontWeight(700)
        Image($r('app.media.img_01'))
          .width(200)
        //控制元素的缩放
          .scale({
            x:this.maskImageX,
            y:this.maskImageY
          })
          .animation({
            duration:500
          })
        Button('开心收下')
          //点击时修改遮罩参数
          .onClick(()=>{
            this.maskOpacity=0
            this.maskzIndex=-1
            this.maskImageX=0
            this.maskImageY=0
          })
          .width(200)
          .height(50)
          .backgroundColor(Color.Transparent)
          .border({width:2,color:'#fff9e0'})




      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
      //颜色十六进制色值,前两位为透明度
      .backgroundColor('#cc000000')
      //设置透明度
      .opacity(this.maskOpacity)
      .zIndex(this.maskzIndex)
      //动画 animation 元素状态发生改变,可以添加animation做动画效果
      .animation({
        duration:300
      })
    }




  }


}

四.随机效果

生成一个0-5的随机数对应六张卡片

需求:

①取随机数 Math.random

console.log('随机数',Math.random())
//向下取整
console.log('随机数',Math.floor(Math.random()))

②控制展示(换图)

③点击收下,卡片数累加

代码示意:

//定义接口(每个列表项的数据结构)
interface ImageCount{
  url:string
  count:number
}
//需求1:点击抽卡,才显示遮罩层
//需求2:图片,要有缩放显示动画
@Entry
@Component
struct Index {
  //随机生肖卡序号0-5
  @State randomIndex:number = -1 //-1表示还没开始抽
  //基于接口ImageCount准备图片数据
  @State images:ImageCount[]=[
    {url:'app.media.bg_00',count:0},
    {url:'app.media.bg_01',count:0},
    {url:'app.media.bg_02',count:0},
    {url:'app.media.bg_03',count:0},
    {url:'app.media.bg_04',count:0},
    {url:'app.media.bg_05',count:0}
  ]
  //控制遮罩层显隐
  @State maskOpacity:number = 0
  @State maskzIndex:number = -1
  //控制图片动画缩放
  @State maskImageX:number = 0
  @State maskImageY:number = 0
  build() {
    Stack(){
      //初始化布局结构
      Column(){


        Grid(){
          ForEach(this.images,(item:ImageCount,index:number)=>{
            GridItem(){
              Badge({
                count:item.count,
                position:BadgePosition.RightTop,
                style:{
                  fontSize:14,
                  badgeSize:20,
                  badgeColor:'#fa2a2d'
                }
              }){
                Image($r(item.url))
                  .width(70)
              }
            }
          })
        }
        .columnsTemplate('1fr 1fr 1fr')
        .rowsTemplate('1fr 1fr')
        .width('100%')
        .height(300)


        Button('立即抽卡')
          //点击时修改遮罩参数
          .onClick(()=>{
            //点击时修改遮罩参数,使遮罩显示
            this.maskOpacity=1
            this.maskzIndex=99
            //点击时的图片缩放动画
            this.maskImageX=1
            this.maskImageY=1
            //随机数生成
            this.randomIndex=Math.floor(Math.random()*6)
          })
          .width(200)
          .backgroundColor('#1d5b8c')
          .margin({top:50})




      }
      .width('100%')
      .height('100%')


      //抽卡遮罩层
      Column({space:30}){
        Text('获得生肖卡')
          .fontColor('#f5ebcf')
          .fontSize(30)
          .fontWeight(700)
        Image($r(`app.media.img_0${this.randomIndex}`))
          .width(200)
        //控制元素的缩放
          .scale({
            x:this.maskImageX,
            y:this.maskImageY
          })
          .animation({
            duration:500
          })
        Button('开心收下')
          //点击时修改遮罩参数
          .onClick(()=>{
            //点击时修改遮罩参数,使遮罩隐藏
            this.maskOpacity=0
            this.maskzIndex=-1
            //点击时的图片缩放动画
            this.maskImageX=0
            this.maskImageY=0
            //开心收下 对象数组的情况需要更新,需要修改替换整个对象
            this.images[this.randomIndex]={
              url:`app.media.img_0${this.randomIndex}`,
              count:this.images[this.randomIndex].count+1
          }
          })
          .width(200)
          .height(50)
          .backgroundColor(Color.Transparent)
          .border({width:2,color:'#fff9e0'})




      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
      //颜色十六进制色值,前两位为透明度
      .backgroundColor('#cc000000')
      //设置透明度
      .opacity(this.maskOpacity)
      .zIndex(this.maskzIndex)
      //动画 animation 元素状态发生改变,可以添加animation做动画效果
      .animation({
        duration:300
      })
    }
  }
}

五.抽大奖遮罩层

1.思路分析:

①布局角度:层叠布局Stack

②结构角度:Column>Text+Image+Button

代码:

Column({space:30}){
        Text('恭喜获得手机一部')
          .fontSize(25)
          .fontColor('#f5ebcf')
          .fontWeight(700)
        Image($r('app.media.hw'))
          .width(300)
        Button('再来一次')
          .width(200)
          .height(50)
          .backgroundColor(Color.Transparent)
          .border({width:2,color:'#fff9e0'})
      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
      .backgroundColor('#cc000000')

2.显隐控制

需求说明:六张卡片集齐-显示中大奖页面

思路:

①准备一个变量,控制显隐

②每次收下一个卡片,判断是否集齐,集齐显示中奖页面

代码:

//控制大奖层显隐
  @State prize:boolean = false


Button('开心收下')//点击时修改遮罩参数
          .onClick(() => {
            //点击时修改遮罩参数,使遮罩隐藏
            this.maskOpacity = 0
            this.maskzIndex = -1
            //点击时的图片缩放动画
            this.maskImageX = 0
            this.maskImageY = 0
            //开心收下 对象数组的情况需要更新,需要修改替换整个对象
            this.images[this.randomIndex] = {
              url: `app.media.img_0${this.randomIndex}`,
              count: this.images[this.randomIndex].count + 1
            }
            //每次收完卡片,需要进行检索是否集齐六张卡片,判断是否集齐了
            //需求:判断数组项的count是否都大于0
            let flag:boolean = true //假设集齐
            //验证是否集齐
            for(let item of this.images){
              if (item.count==0) {
                flag = false
                break //有一个count为0,后续就不需要判断了
              }
            }
            this.prize=flag
          })

3.随机奖品&再来一次

需求1:奖品随机

需求2:再来一次

思路:

1.奖品随机→准备一个奖品数组 Math.random随机取下标

2.再来一次→重置数据

最终代码

//定义接口(每个列表项的数据结构)
interface ImageCount{
  url:string
  count:number
}
//需求1:点击抽卡,才显示遮罩层
//需求2:图片,要有缩放显示动画
@Entry
@Component
struct Index {
  //奖品数组-奖池
  @State prizes:string[]=['pg','hw','xm']
  @State prizeIndex:string='' //默认没有奖
  //随机生肖卡序号0-5
  @State randomIndex:number = -1 //-1表示还没开始抽
  //基于接口ImageCount准备图片数据
  @State images:ImageCount[]=[
    {url:'app.media.bg_00',count:0},
    {url:'app.media.bg_01',count:0},
    {url:'app.media.bg_02',count:0},
    {url:'app.media.bg_03',count:0},
    {url:'app.media.bg_04',count:0},
    {url:'app.media.bg_05',count:0}
  ]
  //控制遮罩层显隐
  @State maskOpacity:number = 0
  @State maskzIndex:number = -1
  //控制图片动画缩放
  @State maskImageX:number = 0
  @State maskImageY:number = 0
  //控制大奖层显隐
  @State prize:boolean = false
  build() {
    Stack() {
      //初始化布局结构
      Column() {


        Grid() {
          ForEach(this.images, (item: ImageCount, index: number) => {
            GridItem() {
              Badge({
                count: item.count,
                position: BadgePosition.RightTop,
                style: {
                  fontSize: 14,
                  badgeSize: 20,
                  badgeColor: '#fa2a2d'
                }
              }) {
                Image($r(item.url))
                  .width(70)
              }
            }
          })
        }
        .columnsTemplate('1fr 1fr 1fr')
        .rowsTemplate('1fr 1fr')
        .width('100%')
        .height(300)


        Button('立即抽卡')//点击时修改遮罩参数
          .onClick(() => {
            //点击时修改遮罩参数,使遮罩显示
            this.maskOpacity = 1
            this.maskzIndex = 99
            //点击时的图片缩放动画
            this.maskImageX = 1
            this.maskImageY = 1
            //随机数生成
            this.randomIndex = Math.floor(Math.random() * 6)
          })
          .width(200)
          .backgroundColor('#1d5b8c')
          .margin({ top: 50 })




      }
      .width('100%')
      .height('100%')


      //抽卡遮罩层
      Column({ space: 30 }) {
        Text('获得生肖卡')
          .fontColor('#f5ebcf')
          .fontSize(30)
          .fontWeight(700)
        Image($r(`app.media.img_0${this.randomIndex}`))
          .width(200)//控制元素的缩放
          .scale({
            x: this.maskImageX,
            y: this.maskImageY
          })
          .animation({
            duration: 500
          })
        Button('开心收下')//点击时修改遮罩参数
          .onClick(() => {
            //点击时修改遮罩参数,使遮罩隐藏
            this.maskOpacity = 0
            this.maskzIndex = -1
            //点击时的图片缩放动画
            this.maskImageX = 0
            this.maskImageY = 0
            //开心收下 对象数组的情况需要更新,需要修改替换整个对象
            this.images[this.randomIndex] = {
              url: `app.media.img_0${this.randomIndex}`,
              count: this.images[this.randomIndex].count + 1
            }
            //每次收完卡片,需要进行检索是否集齐六张卡片,判断是否集齐了
            //需求:判断数组项的count是否都大于0
            let flag:boolean = true //假设集齐
            //验证是否集齐
            for(let item of this.images){
              if (item.count==0) {
                flag = false
                break //有一个count为0,后续就不需要判断了
              }
            }
            this.prize=flag


            //判断是否中奖了 如果是 需要抽奖
            if(flag){
              let randomIndex:number=Math.floor(Math.random()*3)
              this.prizeIndex = this.prizes[randomIndex]
            }
          })
          .width(200)
          .height(50)
          .backgroundColor(Color.Transparent)
          .border({ width: 2, color: '#fff9e0' })




      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
      //颜色十六进制色值,前两位为透明度
      .backgroundColor('#cc000000')
      //设置透明度
      .opacity(this.maskOpacity)
      .zIndex(this.maskzIndex)
      //动画 animation 元素状态发生改变,可以添加animation做动画效果
      .animation({
        duration: 300
      })


      //抽大奖遮罩层
      if (this.prize) {
        Column({ space: 30 }) {
          Text('恭喜获得手机一部')
            .fontSize(25)
            .fontColor('#f5ebcf')
            .fontWeight(700)
          Image($r(`app.media.${this.prizeIndex}`))
            .width(300)
          Button('再来一次')
            .onClick(()=>{
              this.prize = false
              this.prizeIndex=''
              this.images=[
                {url:'app.media.bg_00',count:0},
                {url:'app.media.bg_01',count:0},
                {url:'app.media.bg_02',count:0},
                {url:'app.media.bg_03',count:0},
                {url:'app.media.bg_04',count:0},
                {url:'app.media.bg_05',count:0}
              ]
            })
            .width(200)
            .height(50)
            .backgroundColor(Color.Transparent)
            .border({ width: 2, color: '#fff9e0' })
        }
        .justifyContent(FlexAlign.Center)
        .width('100%')
        .height('100%')
        .backgroundColor('#cc000000')


      }
    }
  }
}

感谢观看,也希望大家可以自己写一写,尝试以下效果,这个案例还是很有趣的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值