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