个人主页→VON
收录专栏→鸿蒙开发小型案例总结
基础语法部分会发布于github 和 gitee上面(暂未发布)
难度系数:
前言
该小游戏使用到的知识点都是一些新的东西,当时写的时候就是一边写一边学习知识点,所以时间上花费的比较多。有些东西是为了简化代码提高可读性,希望大家认真观看认真学习。
构建思路
初始界面
没有抽到任何卡片时的一个界面,这个页面的构建相对简单一些。方法也有很多,初始时的图片是自定义的一张图片,立即抽卡是一个Button组件。
抽取到卡片时的页面
点击开始抽卡的时候会弹出这一界面,原理就是层叠关系的转变以及透明度的更改。点击开心收下时所属卡片的数量会加一,还可以接着抽卡。
获奖页面
当所有卡片都集齐后会有中级大奖,当然这个大奖也是我们自行设计的,这里是以手机为例。这一界面的实现和抽到卡片时的页面原理相同。
界面讲解
1.定义接口并且准备生肖卡片
2.定义初始化页面
3.设定抽卡页面和奖品页面的初始值
4.构建抽卡页面
因为篇幅的原因,将部分代码折叠了起来。
5.中奖页面
6.再来一次
点击再来一次后,所有数据恢复默认值,重新开始游戏
知识点概述
鸿蒙开发中的Grid布局是一种新型的布局方式,通过网格来划分页面,使用行列来定义网格,从而使得页面布局更加灵活、简洁且易于维护。
鸿蒙HarmonyOS中的ArkUI框架提供了Grid和GridItem组件来构建网格布局。Grid作为容器组件,用于设置网格布局的相关参数,而GridItem则定义了子组件的特征。这种布局方式支持自适应布局,能够轻松实现响应式设计,适用于多终端设备显示。
在鸿蒙开发中,网格布局由“行”和“列”分割的单元格组成,每个单元格可以包含不同的元素,如文本、图片和媒体等。Grid组件支持自定义行列数以及每行每列的尺寸占比,并允许设置子组件横跨多行或多列。这种布局不仅具备强大的页面均分能力,还允许开发者精确控制子组件的占比。
网格布局的创建主要通过设置Grid组件的rowsTemplate和columnsTemplate属性来完成。这两个属性的值是由空格和'数字+fr'间隔拼接的字符串,其中fr的数量表示网格的行数或列数。数字表示该行或列在网格布局宽度上的占比,从而决定该行或列的宽度。例如,一个三行三列的网格布局,垂直方向上分为三等份,每行占一份;水平方向上分为四等份,第一列占一份,第二列占两份,第三列占一份。这可以通过设置rowsTemplate为'1fr 1fr 1fr'和columnsTemplate为'1fr 2fr 1fr'来实现。
为了进一步细化子组件的布局,GridItem组件提供了rowStart、rowEnd、columnStart和columnEnd等属性。这些属性分别指定当前子组件的起始行号、终点行号、起始列号和终点列号。例如,如果一个子组件需要横跨第一列和第二列,可以将其columnStart和columnEnd分别设置为1和2。同理,如果一个子组件需要横跨第五行和第六行,可以将其rowStart和rowEnd分别设置为5和6。
此外,Grid组件还支持设置排列方式和主轴方向。通过layoutDirection属性,可以设定网格布局的主轴方向,并决定子组件的排列方式。当layoutDirection设为Row时,子组件会从左到右排列,排满一行再排下一行;设为Column时,子组件会从上到下排列,排满一列再排下一列。结合minCount和maxCount属性,可以约束主轴方向上的网格数量。
鸿蒙开发中的Grid布局提供了一种强大且灵活的方式来组织和管理页面元素。通过合理应用Grid和GridItem组件的属性及方法,开发者可以构建出多样化的网格布局,满足不同场景的应用需求。
Grid容器组件
- 基本概念:
Grid
是一个容器,由行和列组成的单元格构成。- 通过指定每个子组件
GridItem
所在的单元格位置来实现灵活多变的布局效果。
属性
-
rowsTemplate 和 columnsTemplate:
- 这两个属性用来定义网格的行和列模板。例如,你可以定义等宽的列或等高的行,或者混合使用固定尺寸和可伸缩的单元格。
-
rowsGap 和 columnsGap:
- 这两个属性用来设置行与行之间以及列与列之间的间隙大小。
-
layoutDirection:
- 决定网格中元素的排列方向,默认为水平方向(Row),也可以设置为垂直方向(Column)。
子组件 GridItem
GridItem
是Grid
容器的直接子组件,用来表示网格中的一个单元格。- 你可以在
GridItem
中放置任何其他组件,并且可以指定其跨越多少行或列。
代码展示
// 1.定义接口
interface Images{
url:string
count:number
}
// 需求1:遮罩层显隐 透明度opacity 0-1 层级zInsex 1-99
// 需求2:图片收缩 缩放scale 0-1
@Entry
@Component
struct Index {
// 随机的生肖卡序号
@State randomNum:number=-1// 初始值为-1表示还没有抽卡
// 2.基于接口准备数据
@State images:Images[]=[
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0}
]
// 透明度
@State transparent:number=0 // 初始为0
//层级
@State Level:number=0 // 初始为0
// 缩放
@State zoomx:number=0
@State zoomy:number=0
// 控制中奖
@State isGet:boolean=false
// 奖池
@State arr:string[]=['pg','hw','xm']
@State price:string=''//默认没有中奖
build() {
// 层叠布局
Stack(){
// 初始化页面
Column(){
// Grid布局的基础使用:规则的行列布局中非常常见
Grid(){
ForEach(this.images,(item:Images,index:number)=>{
GridItem(){
Badge({
count:item.count,
position:BadgePosition.RightTop,
style:{
fontSize:14,
badgeSize:20,
badgeColor:Color.Red
}
}){
Image($r(item.url))
.width(100)
.height(100)
}
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.width('100%')
.height(300)
.margin({top:100})
Button('立即抽卡')
.width(200)
.backgroundColor('#de668d')
.margin({top:50})
.onClick(()=>{
this.Level=99
this.transparent=1
this.zoomx=1
this.zoomy=1
//计算随机数
this.randomNum = Math.floor(Math.random()*6)
})
}
.zIndex(5) // 初始化层级为5
.width('100%')
.height('100%')
// 抽卡时的页面
Column({space:25}){
Text('获得生肖卡片')
.fontColor('#f5ebcf')
.fontSize(25)
.fontWeight(FontWeight.Bold)
Image($r(`app.media.sxcard0${this.randomNum}`))
.width(200)
// 卡片的播放
.scale({
x:this.zoomx,
y:this.zoomy
})
.animation({
duration:500
})
Button('开心收下')
.width(200)
.height(50)
.backgroundColor(Color.Transparent)// 透明色
.border({width:2,color:'#fff9e0'})
.onClick(()=>{
this.transparent=0
this.Level=0
this.zoomx=0
this.zoomy=0
// 开心收下
this.images[this.randomNum]={
url:`app.media.sxcard0${this.randomNum}`,
count:this.images[this.randomNum].count+1
}
// 判断卡片的数量
// 如果卡片中有一个的数量为0,那就是没集齐
let flag:boolean=true
for(let item of this.images){
if(item.count==0){
flag=false
break
}
}
this.isGet=flag
if(flag){
let randomIndex:number=Math.floor(Math.random()*3)
this.price=this.arr[randomIndex]
}
})
}
.justifyContent(FlexAlign.Center)// 居中对齐
.width('100%')
.height('100%')
.backgroundColor('#cc000000')
.zIndex(this.Level)
.opacity(this.transparent)// 透明度
// 动画
.animation({
duration:200
})
if(this.isGet){
// 中奖页面
Column(){
Text('恭喜获得手机一部')
.fontColor('#f5ebcf')
.fontSize(25)
.fontWeight(700)
Image($r(`app.media.sxcard_${this.price}`))
.width(300)
Button('再来一次')
.width(200)
.height(50)
.backgroundColor(Color.Transparent)
.border({width:2,color:'#fff9e0'})
.onClick(()=>{
this.isGet=false
this.price=''
this.images=[
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0},
{url:'app.media.sxcard',count:0}
]
})
}
.zIndex(10)
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#cc000000')
}
}
}
}