案例源码:
Zodiac_cards: 鸿蒙生肖抽奖卡片
效果演示
初始布局
1. Badge 角标组件
此处为语雀内容卡片,点击链接查看:https://www.yuque.com/kevin-nzthp/lvl039/rccg0o4pkp3v6nua
2. Grid 布局
// 定义接口
interface ImageCount {
url: ResourceStr,
count: number
}
@Entry
@Component
struct Index {
@State images: ImageCount[] = [
{ url: '/images/bg_00.png', count: 0 },
{ url: '/images/bg_01.png', count: 1 },
{ url: '/images/bg_02.png', count: 2 },
{ url: '/images/bg_03.png', count: 3 },
{ url: '/images/bg_04.png', count: 4 },
{ url: '/images/bg_05.png', count: 5 },
]
// 控制遮罩的显隐
@State maskOpacity: number = 0 // 透明度
@State maskIndex: number = -1; // 显示层级
// 控制图片的缩放
@State maskImgX: number = 0 // 水平缩放比
@State maskImgY: number = 0 // 垂直缩放比
build() {
Stack() {
Column() {
Grid() {
ForEach(this.images, (item: ImageCount) => {
GridItem() {
Badge({
count: item.count,
position: BadgePosition.RightTop,
style: {
badgeSize: this.maskImgX,
fontSize: this.maskImgY
}
}) {
Image(item.url)
.width(80)
}
}
})
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.width('100%')
.height(300)
.margin({ top: 100 })
Button('立即抽卡')
.width(200)
.backgroundColor('#ed5b8c')
.margin({ top: 50 })
.onClick(()=>{
// 点击时,修改遮罩参数,让遮罩显示
this.maskOpacity = 1
this.maskIndex = 99
// 图片需要缩放
this.maskImgX = 1
this.maskImgY = 1
})
}
.width('100%')
.height('100%')
.backgroundColor(Color.Pink)
// 抽卡遮盖层
Column({space: 30}) {
Text('获得生肖卡')
.fontColor('#f5ebcf')
.fontSize(25)
.fontWeight(FontWeight.Bold)
Image('/images/img_00.png')
.width(200)
//控制元素的缩放
.scale({
x: this.maskImgX,
y: this.maskImgY
})
Button('开心收下')
.width(200)
.height(50)
.backgroundColor(Color.Transparent)
.border({ width: 2 ,color:'#fff9e0'})
.onClick(()=>{
// 控制弹层显隐
this.maskOpacity = 0
this.maskIndex = -1
// 重置缩放比为0,便于下一次进行缩放
this.maskImgX = 0
this.maskImgY = 0
})
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
.backgroundColor('#cc000000')
// 设置透明度
.opacity(this.maskOpacity)
.zIndex(this.maskIndex)
// 动画 animation 当我们元素有状态的改变,可以添加animation做动画
.animation({
duration: 500
})
}
}
}
抽卡遮罩层
静态页面
点击立即抽卡按钮后,会进入遮罩层,显示抽取的卡片,此时抽卡的页面转换为背景图,使用层叠布局
// 定义图片接口
interface ImageCount {
url: ResourceStr,
count: number
}
@Entry
@Component
struct Index {
// 定义图片渲染数组
@State images: ImageCount[] = [
{ url: '/images/bg_00.png', count: 0 },
{ url: '/images/bg_01.png', count: 1 },
{ url: '/images/bg_02.png', count: 2 },
{ url: '/images/bg_03.png', count: 3 },
{ url: '/images/bg_04.png', count: 4 },
{ url: '/images/bg_05.png', count: 5 },
]
build() {
Stack(){
Column() {
Grid() {
ForEach(this.images, (item: ImageCount) => {
GridItem() {
Badge({
count: item.count,
position: BadgePosition.RightTop,
style: {
fontSize: 12,
badgeSize: 16
}
}) {
Image(item.url)
.width(80)
}
}
})
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.height(300)
.margin({top: 50, bottom: 50})
// .backgroundColor(Color.Pink)
Button('立即抽卡')
.width(200)
.backgroundColor('#ED5B8C')
}
Column({space: 30}){
Text('获得生肖卡')
.fontColor('#F3EAD3')
.fontWeight(700)
.fontSize(24)
Image('/images/img_00.png')
.width(200)
Button('开心收下')
.width(200)
.border({
width: 2,
color:'#9F9C90',
})
.backgroundColor(Color.Transparent)
}
.backgroundColor('#cc000000')
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
}
抽卡遮罩层- 显隐效果控制
添加状态变量控制遮罩层 Z 轴 和 不透明度的数值.
当点击 “立即抽卡”按钮时,显示遮罩层。(此时不能隐藏)
当点击 遮罩层“开心收下”按钮时,隐藏遮罩层。
添加动画
添加遮罩层图片的缩放
效果
// 定义图片接口
interface ImageCount {
url: ResourceStr,
count: number
}
@Entry
@Component
struct Index {
// 定义图片渲染数组
@State images: ImageCount[] = [
{ url: '/images/bg_00.png', count: 0 },
{ url: '/images/bg_01.png', count: 1 },
{ url: '/images/bg_02.png', count: 2 },
{ url: '/images/bg_03.png', count: 3 },
{ url: '/images/bg_04.png', count: 4 },
{ url: '/images/bg_05.png', count: 5 },
]
// 控制遮罩的显隐
@State maskOpacity: number = 0 // 透明度
@State maskIndex: number = -1; // 显示层级
// 控制遮罩层图片的缩放
@State maskImgScaleX: number = 0 // 水平缩放比
@State maskImgScaleY: number = 0 // 垂直缩放比
// 获取图片
build() {
Stack() {
// 抽卡层
Column() {
Grid() {
ForEach(this.images, (item: ImageCount) => {
GridItem() {
Badge({
count: item.count,
position: BadgePosition.RightTop,
style: {
fontSize: 12,
badgeSize: 16
}
}) {
Image(item.url)
.width(80)
}
}
})
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.height(300)
.margin({ top: 50, bottom: 50 })
// .backgroundColor(Color.Pink)
Button('立即抽卡')
.width(200)
.backgroundColor('#ED5B8C')
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩显示
this.maskOpacity = 1
this.maskIndex = 99
// 点击时修改遮罩层图片的缩放比
this.maskImgScaleX = 1
this.maskImgScaleY = 1
})
}
// 遮罩层
Column({ space: 30 }) {
Text('获得生肖卡')
.fontColor('#F3EAD3')
.fontWeight(700)
.fontSize(24)
Image('/images/img_00.png')
.width(200)
.scale({
//控制图片的缩放
x: this.maskImgScaleX,
y: this.maskImgScaleY
})
.animation({
// 动画
duration: 500
})
Button('开心收下')
.width(200)
.border({
width: 2,
color: '#9F9C90',
})
.backgroundColor(Color.Transparent)
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩隐藏
this.maskOpacity = 0
this.maskIndex = -1
// // 点击时修改遮罩层图片的缩放比为1:1
this.maskImgScaleX = 0
this.maskImgScaleY = 0
})
}
.zIndex(this.maskIndex)
.opacity(this.maskOpacity)
.backgroundColor('#cc000000')
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
}
随机卡片
效果演示:
要获得 0-5 的整数索引,随机抽取卡片
此时可以获取随机卡片,接下来要将抽到的随机卡片显示在主页面并右上角角标显示。
// 定义图片接口
interface ImageCount {
url: ResourceStr,
count: number
}
@Entry
@Component
struct Index {
// 定义图片渲染数组
@State images: ImageCount[] = [
{ url: '/images/bg_00.png', count: 0 },
{ url: '/images/bg_01.png', count: 0 },
{ url: '/images/bg_02.png', count: 0 },
{ url: '/images/bg_03.png', count: 0 },
{ url: '/images/bg_04.png', count: 0 },
{ url: '/images/bg_05.png', count: 0 },
]
// 控制遮罩的显隐
@State maskOpacity: number = 0 // 透明度
@State maskIndex: number = -1; // 显示层级
// 控制遮罩层图片的缩放
@State maskImgScaleX: number = 0 // 水平缩放比
@State maskImgScaleY: number = 0 // 垂直缩放比
// 获取遮罩层选择的图片Index
@State maskImgIndex: number = 0
build() {
Stack() {
// 抽卡层
Column() {
Grid() {
ForEach(this.images, (item: ImageCount) => {
GridItem() {
Badge({
count: item.count,
position: BadgePosition.RightTop,
style: {
fontSize: 12,
badgeSize: 16
}
}) {
Image(item.url)
.width(80)
}
}
})
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.height(300)
.margin({ top: 50, bottom: 50 })
// .backgroundColor(Color.Pink)
Button('立即抽卡')
.width(200)
.backgroundColor('#ED5B8C')
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩显示
this.maskOpacity = 1
this.maskIndex = 99
// 点击时修改遮罩层图片的缩放比
this.maskImgScaleX = 1
this.maskImgScaleY = 1
// // 随机获取图片的Index
this.maskImgIndex = Math.floor(Math.random() * 6)
})
}
// 遮罩层
Column({ space: 30 }) {
Text('获得生肖卡')
.fontColor('#F3EAD3')
.fontWeight(700)
.fontSize(24)
Image(`/images/img_0${this.maskImgIndex}.png`)
.width(200)
.scale({
//控制图片的缩放
x: this.maskImgScaleX,
y: this.maskImgScaleY
})
.animation({
// 动画
duration: 500
})
Button('开心收下')
.width(200)
.border({
width: 2,
color: '#9F9C90',
})
.backgroundColor(Color.Transparent)
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩隐藏
this.maskOpacity = 0
this.maskIndex = -1
// // 点击时修改遮罩层图片的缩放比为1:1
this.maskImgScaleX = 0
this.maskImgScaleY = 0
// 开心收下
this.images[this.maskImgIndex] = {
url: `/images/img_0${this.maskImgIndex}.png`,
count: this.images[this.maskImgIndex].count + 1
}
})
}
.zIndex(this.maskIndex)
.opacity(this.maskOpacity)
.backgroundColor('#cc000000')
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
}
抽大奖遮罩层
静态页面
// 定义图片接口
interface ImageCount {
url: ResourceStr,
count: number
}
@Entry
@Component
struct Index {
// 定义图片渲染数组
@State images: ImageCount[] = [
{ url: '/images/bg_00.png', count: 0 },
{ url: '/images/bg_01.png', count: 0 },
{ url: '/images/bg_02.png', count: 0 },
{ url: '/images/bg_03.png', count: 0 },
{ url: '/images/bg_04.png', count: 0 },
{ url: '/images/bg_05.png', count: 0 },
]
// 控制遮罩的显隐
@State maskOpacity: number = 0 // 透明度
@State maskIndex: number = -1; // 显示层级
// 控制遮罩层图片的缩放
@State maskImgScaleX: number = 0 // 水平缩放比
@State maskImgScaleY: number = 0 // 垂直缩放比
// 获取遮罩层选择的图片Index
@State maskImgIndex: number = 0
build() {
Stack() {
// 抽卡层
Column() {
Grid() {
ForEach(this.images, (item: ImageCount) => {
GridItem() {
Badge({
count: item.count,
position: BadgePosition.RightTop,
style: {
fontSize: 12,
badgeSize: 16
}
}) {
Image(item.url)
.width(80)
}
}
})
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.height(300)
.margin({ top: 50, bottom: 50 })
// .backgroundColor(Color.Pink)
Button('立即抽卡')
.width(200)
.backgroundColor('#ED5B8C')
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩显示
this.maskOpacity = 1
this.maskIndex = 99
// 点击时修改遮罩层图片的缩放比
this.maskImgScaleX = 1
this.maskImgScaleY = 1
// // 随机获取图片的Index
this.maskImgIndex = Math.floor(Math.random() * 6)
})
}
// 遮罩层
Column({ space: 30 }) {
Text('获得生肖卡')
.fontColor('#F3EAD3')
.fontWeight(700)
.fontSize(24)
Image(`/images/img_0${this.maskImgIndex}.png`)
.width(200)
.scale({
//控制图片的缩放
x: this.maskImgScaleX,
y: this.maskImgScaleY
})
.animation({
// 动画
duration: 500
})
Button('开心收下')
.width(200)
.border({
width: 2,
color: '#9F9C90',
})
.backgroundColor(Color.Transparent)
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩隐藏
this.maskOpacity = 0
this.maskIndex = -1
// // 点击时修改遮罩层图片的缩放比为1:1
this.maskImgScaleX = 0
this.maskImgScaleY = 0
// 开心收下
this.images[this.maskImgIndex] = {
url: `/images/img_0${this.maskImgIndex}.png`,
count: this.images[this.maskImgIndex].count + 1
}
})
}
.zIndex(this.maskIndex)
.opacity(this.maskOpacity)
.backgroundColor('#cc000000')
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
// 抽大奖遮罩层
Column({space: 30}) {
Text('恭喜获得手机一部')
.fontColor('#E4DDC7')
.fontWeight(700)
.fontSize(25)
Image('/images/hw.png')
.width(300)
Button('再来一次')
.width(200)
.height(50)
.border({
width: 2,
color: '#E4DDC7'
})
.backgroundColor(Color.Transparent)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
.backgroundColor('#cc000000')
}
}
}
抽大奖遮罩层的显隐
前提:
六张卡片集齐,显示 --- 中大奖页面
默认为 false,不显示此抽大奖遮罩层
判断数组项的count, 是否都大于0, 只能有一个等于0,就意味着没及其
最终效果演示
随机奖品 & 再来一次
奖品随机抽 -》准备一个奖品数组, Math
再来一次 -》重置数据
奖品随机抽
准备奖品数组,默认抽中的奖品为空
准备随机数
在“”开心收下“”按钮下,判断是否中奖,如果中奖了,准备抽奖。
效果:
再来一次
将数据重置
效果演示:
完整代码:
import { trustedAppService } from '@kit.DeviceSecurityKit';
// 定义图片接口
interface ImageCount {
url: ResourceStr,
count: number
}
@Entry
@Component
struct Index {
// 定义图片渲染数组
@State images: ImageCount[] = [
{ url: '/images/bg_00.png', count: 0 },
{ url: '/images/bg_01.png', count: 0 },
{ url: '/images/bg_02.png', count: 0 },
{ url: '/images/bg_03.png', count: 0 },
{ url: '/images/bg_04.png', count: 0 },
{ url: '/images/bg_05.png', count: 0 },
]
// 奖品池
@State prizePool: string[] = [
'/images/pg.png',
'/images/hw.png',
'/images/xm.png'
]
//抽中的奖品
@State prize: string = '' // 默认没中奖
// 控制遮罩的显隐
@State maskOpacity: number = 0 // 透明度
@State maskIndex: number = -1; // 显示层级
// 控制遮罩层图片的缩放
@State maskImgScaleX: number = 0 // 水平缩放比
@State maskImgScaleY: number = 0 // 垂直缩放比
// 获取遮罩层选择的图片Index
@State maskImgIndex: number = 0
// 控制中大奖的显隐
@State isGet: boolean = false // 中大奖显隐
build() {
Stack() {
// 抽卡层
Column() {
Grid() {
ForEach(this.images, (item: ImageCount) => {
GridItem() {
Badge({
count: item.count,
position: BadgePosition.RightTop,
style: {
fontSize: 12,
badgeSize: 16
}
}) {
Image(item.url)
.width(80)
}
}
})
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.height(300)
.margin({ top: 50, bottom: 50 })
// .backgroundColor(Color.Pink)
Button('立即抽卡')
.width(200)
.backgroundColor('#ED5B8C')
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩显示
this.maskOpacity = 1
this.maskIndex = 99
// 点击时修改遮罩层图片的缩放比
this.maskImgScaleX = 1
this.maskImgScaleY = 1
// // 随机获取图片的Index
this.maskImgIndex = Math.floor(Math.random() * 6)
})
}
// 遮罩层
Column({ space: 30 }) {
Text('获得生肖卡')
.fontColor('#F3EAD3')
.fontWeight(700)
.fontSize(24)
Image(`/images/img_0${this.maskImgIndex}.png`)
.width(200)
.scale({
//控制图片的缩放
x: this.maskImgScaleX,
y: this.maskImgScaleY
})
.animation({
// 动画
duration: 500
})
Button('开心收下')
.width(200)
.border({
width: 2,
color: '#9F9C90',
})
.backgroundColor(Color.Transparent)
.onClick(() => {
// 点击时,修改遮罩参数,让遮罩隐藏
this.maskOpacity = 0
this.maskIndex = -1
// // 点击时修改遮罩层图片的缩放比为1:1
this.maskImgScaleX = 0
this.maskImgScaleY = 0
// 开心收下
this.images[this.maskImgIndex] = {
url: `/images/img_0${this.maskImgIndex}.png`,
count: this.images[this.maskImgIndex].count + 1
}
// 每次收完,要进行简单检索,判断是否集齐
// 需求:判断数组项的count, 是否都大于0, 只能有一个等于0,就意味着没及其
let flag: boolean = true // 假设集齐
// 验证是否集齐
for (let item of this.images) {
if (item.count === 0) {
flag = false // 没集齐
break; // 只要没集齐,便可退出循环
}
}
this.isGet = flag
if (flag) {
let randIndex: number = Math.floor(Math.random() * 3)
this.prize = this.prizePool[randIndex]
}
})
}
.zIndex(this.maskIndex)
.opacity(this.maskOpacity)
.backgroundColor('#cc000000')
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
// 抽大奖遮罩层
if (this.isGet) {
Column({ space: 30 }) {
Text('恭喜获得手机一部')
.fontColor('#E4DDC7')
.fontWeight(700)
.fontSize(25)
Image(this.prize)
.width(300)
Button('再来一次')
.width(200)
.height(50)
.border({
width: 2,
color: '#E4DDC7'
})
.backgroundColor(Color.Transparent)
.onClick(() => {
this.isGet = false
this.prize = ''
this.images = [
{ url: '/images/bg_00.png', count: 0 },
{ url: '/images/bg_01.png', count: 0 },
{ url: '/images/bg_02.png', count: 0 },
{ url: '/images/bg_03.png', count: 0 },
{ url: '/images/bg_04.png', count: 0 },
{ url: '/images/bg_05.png', count: 0 },
]
})
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
.backgroundColor('#cc000000')
}
}
}
}