使用仓颉语言开发鸿蒙应用-初窥门径
前言
之前写了一系列的仓颉语言教程,虽然它既能用于鸿蒙应用开发,也能用于服务端开发。但我作为一个移动端开发人员来讲,还是着重于仓颉语言在鸿蒙应用开发中的应用。
在这里,我们移植一个Emacs上简单的55小游戏。有的地方也称为开关灯、开关窗等。
具体规则如下:
在一个55的二维矩阵中,初始都为黑色,点击某一个格子,则它自己和它上下左右的格子都变成红色(如果已经是红色,则变为黑色)。继续点击不同的格子,直到所有的格子都变成红色。
比如初始都为黑色,以左上角为[0,0]
,右下角为[4,4]
。当点击 [1,1]
处的格子,则[1,0]
[0,1]
[1,1]
,[1,2]
,[2,1]
都由黑色变为红色。
这时在点击
[0,0]
, 则[0,0]
由黑色变为红色。[0,1]
和 [1,0]
则由红色变为黑色
我们的目的就是让格子都变为红色。
规则介绍完了,我们开始写代码
开始
最简单的方法就是使用布尔类型的二维数组来保存状态,点击时将它本身和上下左右的值取反就可以了。
布局可以搞两个ForEach循环渲染。
创建项目
在windows上使用DevEco Studio 6.0.0 Release
版本创建仓颉项目失败,只能安装5.1.0
版本了。
有知道原因的朋友可以评论留言指导一下。
创建项目和ArkTS项目差不多,跟着提示走就行了,这里不再赘述。
写代码
我们先写点代码整体感受一下,先不用关心其他的文件是做什么的。
找到entry->src->main->cangjie->index.cj
这个文件开始写代码。
首先声明一个二维数组,需要注意的是,在仓颉中,如果想要观察数组中元素、数组大小的变化,需要使用ObservedArray
或者ObservedArrayList
,他们是状态管理的数组类型,当其中数组发生变化时,如修改其中一项的值,删除或添加一项,就会触发UI更新。
@State
var status: ObservedArray<ObservedArray<Bool>> = ObservedArray<ObservedArray<Bool>>(
[
ObservedArray<Bool>([false, false, false, false, false]),
ObservedArray<Bool>([false, false, false, false, false]),
ObservedArray<Bool>([false, false, false, false, false]),
ObservedArray<Bool>([false, false, false, false, false]),
ObservedArray<Bool>([false, false, false, false, false])
]
)
仓颉中的组件写法和ArkTS中基本一致,不一致也是语法上的不一致。
我们先添加一个标题
func build() {
Column {
Row() {
Text("Emacs 5x5 小游戏").fontSize(18)
}.width(100.percent).justifyContent(FlexAlign.Center)
}
}
使用关键字func
声明函数,在ArkTS中的width("100%")
改为了width(100.percent)
。其他的属性保持了一致。
我们接着添加两个ForEach循环,先看一下函数类型
ForEach(dataSource: ArrayList<T>, itemGeneratorFunc: (T, Int64) -> Unit, keyGeneratorFunc: (T, Int64) -> String)
第一个参数是数据源,第二个参数是一个用于生成组件的函数,第三个参数是用于生成key的函数,和ArkTS中是一致的。
ForEach(
status,
{
state: ObservedArray<Bool>, rowIndex: Int64 => Row() {
ForEach(state, {current: Bool, columIndex: Int64 => Rect()})
}
}
)
第一个循环生成Row()
,第二个循环在每一个Row
中生成Rect()
。
然后我们根据状态来给Rect添加颜色:
func getColor(light: Bool): Color {
if (light) {
return Color.RED
}
return Color.BLACK
}
ForEach(
status,
{
state: ObservedArray<Bool>, rowIndex: Int64 => Row() {
ForEach(
state,
{
current: Bool, columIndex: Int64 => Rect()
.width(50)
.height(50)
.fill(getColor(current))
.borderColor(Color.WHITE)
.borderWidth(1)
}
)
}
}
)
这里需要注意一点,如果需要自定义key生成器,需要这么写:
ForEach(
status,
itemGeneratorFunc: { //itemGeneratorFunc 可以不写
state: ObservedArray<Bool>, rowIndex: Int64 => Row() {}
},
keyGeneratorFunc:{
state: ObservedArray<Bool>, rowIndex: Int64 => return "keyGeneratorFunc"
}
)
而不能写成
ForEach(
status,
{
state: ObservedArray<Bool>, rowIndex: Int64 => Row() {}
},
{
state: ObservedArray<Bool>, rowIndex: Int64 => return "keyGeneratorFunc"
}
)
会提示positional argument cannot appear after named argument
翻译过来就是位置参数不能出现在命名参数之后
点击事件
接下来我们添加一下点击事件
.onClick {
_ =>
AppLog.error("AppLog 点击了${rowIndex} ${columIndex}")
Hilog.error(0x01, "huangyuan", "点击了${rowIndex} ${columIndex}")
status[rowIndex][columIndex] = !status[rowIndex][columIndex]
if (rowIndex - 1 >= 0) {
status[rowIndex - 1][columIndex] = !status[rowIndex - 1][columIndex]
}
if (columIndex - 1 >= 0) {
status[rowIndex][columIndex - 1] = !status[rowIndex][columIndex - 1]
}
if (rowIndex + 1 <= 4) {
status[rowIndex + 1][columIndex] = !status[rowIndex + 1][columIndex]
}
if (columIndex + 1 <= 4) {
status[rowIndex][columIndex + 1] = !status[rowIndex][columIndex + 1]
}
if (checkResult()) {
PromptAction.showToast(message: "success", duration: 1500, bottom: "80vp")
}
showStatus()
}
这里打印日志有两种方案,一种是用AppLog
,另外一种就是延续ArkTS中Hilog
。
代码也很简单,就是按照前面的规则来修改对应位置的值。
这里有一个checkResult()
的函数调用,当二维数组中的值全部为true
时则弹出toast
提示成功
func checkResult(): Bool {
var success = true
for (row in 0..status.size) {
for (colum in 0..status[row].size) {
if (!status[row][colum]) {
success = false
break
}
}
if (!success) {
break
}
}
return success
}
这里有一点需要注意:由于ObservedArray
没有实现Iterator
,因此不能使用for(xx in status)
方式进行遍历。showStatus()
函数则是打印当前的状态,没啥特殊的
func showStatus() {
var result = ""
for (row in 0..status.size) {
for (colum in 0..status[row].size) {
if (status[row][colum]) {
result += "红 "
} else {
result += "黑 "
}
}
result += "\n"
}
Hilog.error(0x01, "huangyuan", result)
}
这样我们就完成了小游戏的主体功能。看下效果
第一篇完结撒花
更多推荐
所有评论(0)