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

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

时间:2024-09-10 21:52:59浏览次数:14  
标签:count 遮罩 06 url media app 星河 NEXT width

序言:

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

笔者也是跟着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')


      }
    }
  }
}

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

标签:count,遮罩,06,url,media,app,星河,NEXT,width
From: https://blog.csdn.net/Bew1tch/article/details/142110102

相关文章

  • [ARC106F] Figures 题解
    生成函数大法好。思路考虑prufer序列。如果\(n\)个点的度数确定,那么生成树个数为:\[\frac{(n-2)!}{\prod(d_i-1)}\]那么在此题中,\(n\)个点的度数确定,那么方案数为:\[\frac{(n-2)!}{\prod(d_i-1)}\prod\frac{a_i!}{(a_i-d_i)!}\]其中,\(\sumd_i=2\timesn-2\)。容易发......
  • leetcode day06 动态规划之解码方法I和II
    91.解码方法该题类似于爬楼梯方法一:动态规划对于给定的字符串s,设它的长度为n,其中的字符从左到右依次为s[1],s[2],⋯,s[n]。我们可以使用动态规划的方法计算出字符串s的解码方法数。具体地,设f i 表示字符串s的前i个字符s[1..i]的解码方法数。在进行状态转移......
  • jsp超市管理系统06c97 本系统(程序+源码+数据库+调试部署+开发环境)
    jsp超市管理系统06c97本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能商品分类,员工,库存信息,进货信息,销售信息技术要求:   开发语言:JSP前端使用:HTML5,CSS,JSP动态网页技术后端使用SpringBo......
  • 06JAVA第一次考试选择
    判断正确1,不含公共类的JAVA源文件名称可以随便命名,不受任何限制。2,编译当前路径下的HelloWorld.java文件,使用的命令是:javacHelloWorld.java。3,JamesGosling是Java语言的创始人之一。4,Java语言的标识符区分大小写。5,java.lang包的Character类的isJavaIdentifierStart方......
  • Day06.Java流程控制2
    Java流程控制循环结构While循环while(布尔表达式){//循环内容}最基本的循环只要布尔表达式为true,循环就会一直执行下去我们大多数情况会让循环停止下来,我们需要一个让表达式失效的方式来结束循环少数情况需要循环一直执行,比如服务器的请求响应监听等循环条件一直......
  • EATON EUC-7-100650008电源高压板
    EATON品牌的EUC-7-100650008控制板是一种用于车辆控制系统的电子设备。这些功能是基于EATON品牌在车辆控制系统中的产品特点:控制执行:控制板通常负责接收来自车辆传感器的信息,并根据这些信息控制车辆的执行器,如油门、制动器和转向系统,以确保车辆按照预定的方式运行。系统管理......
  • 20240910_104851 mysql 存储过程 2006班
    修改结束符号delimiter新符号创建一个存储过程要求:查询所有的老师信息只显示id与nameDELIMITER$CREATEPROCEDUREshow1()BEGIN SELECTid,NAMEFROMteacher;END$使用存储过程CALLshow1();查看存储过程的创建语句查看名为p1的存储过程的名称showcreatep......
  • 06 面向对象的软件工程OOSE
    面向对象的软件工程(OOSE,Object-OrientedSoftwareEngineering)是一种用于开发软件系统的工程方法论,它强调使用面向对象的技术和方法来设计和实现软件。以下是关于OOSE的详细介绍:一、定义与特点定义:OOSE是一种将面向对象的思想应用于软件开发过程中的系统方法,它利用对象、类、......
  • 2024.09.10 0650版
    起于《海奥华预言》的思考◆地球管理结构和参考持续更新中...... 英文地址:https://github.com/zhuyongzhe/Earth/tags中文地址:https://www.cnblogs.com/zhuyongzhe85作者:朱永哲 -------------------------------------------------------------------------------------......
  • 数组与贪心算法——452、435、646、406、169(1简4中)
    452.用最少数量的箭引爆气球(中等)有一些球形气球贴在一堵用XY平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i]=[xstart,xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切y坐标。一支弓箭可以沿着x轴从不同点 完全......