话不多说,我们先展示一下运行效果嘿嘿
我们可以随便添加新的任务,可以勾选任务,也可以随时向左划去删除该任务:




首先呢,我们得先创建一个任务类,初始值我们定义为布尔值boolean = false,我们通过改变布尔值的方式去修改任务的状态.
这是代码:
// 任务类
class Task{
static id: number = 1
// 任务名称
name: string = `任务${Task.id++}`
// 任务状态: 是否完成
finished: boolean = false
}
接下来这个很好理解, 去设置一个@Style, 控制每一个任务的样式,这样可以让我们的代码更为简洁。 我们一会需要的时候,直接调用这个函数去修饰每个任务小板块的样式就可以了。
// 统一的卡片样式
@Styles function card(){
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({radius: 6, color:'#1F000000',offsetX:2,offsetY:4})
}
接下来我们直接初始化这些变量。 finishedTask 其实是左边这个数字, totalTask是右边的这个数字。 当我们增加删除任务的时候,进度条也会随之改变。
@Entry
@Component
struct PropPage{
// 总任务数量
@State totalTask: number = 0
// 已完成任务数量
@State finishedTask: number = 0
// 任务数组
@State tasks: Task[] = []
}
每一次改变,我们都会触发这个函数。
// 任务修改时候触发的一个函数
handleTaskChange(){
// 2. 更新任务总数量
this.totalTask = this.tasks.length
// 2. 更新已经完成函数的数量
this.finishedTask = this.tasks.filter(item=>item.finished).length
}
首先我们先写任务进程部分, 因为要逐一解释一些关键字,所以我代码注释写的非常清楚,这里我就不过多解释了:
// 现在我用这个容器 Stack(){.......} 将我的进度条以及这个百分比的进度值堆在一起, 这样进度条就和进度值重叠了。
Stack(){
// 进度条的写法是 Progress({.......}) 在这里我选的是环形进度条
Progress({
value:this.finishedTask,
total:this.totalTask,
type: ProgressType.Ring
})
.width(100)
// 因为我用了 .justifyContent(FlexAlign.SpaceEvenly) 这个属性,它是用于平均分配的。 假设
// 这里我不使用 Row() 再去把这个进度数字弄成一行,会导致百分比左右两边的数字隔的比较远。
Row(){
Text(this.finishedTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / '+this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({top:20,bottom:30})
.justifyContent(FlexAlign.SpaceEvenly)
接着我们新增按钮,当按一下按钮,我们就可以新增一个任务。当然这个按钮新增完数据后,紧跟着就得更改进度条,让其保持一致性。 更改进度条方法很简单,调用刚刚写好的那个 handleTaskChange 函数就行了。
// 2.新增任务按钮
Button('新增任务')
.width(200)
.onClick(()=>{
// 1. 新增任务数据
this.tasks.push(new Task())
// 2. 更新任务总数量
// this.totalTask = this.tasks.length
// 上面这句省略了,增加函数的复用性, 专门写了个函数让我们来调用,功能和上面一样
this.handleTaskChange()
})
好了,我们重头戏就在这里。 我的注释这块写的非常非常详细,大家有问题可以仔细阅读。
// 3. 任务列表, 遍历每一个新增的任务
// 第一假如新增任务溢出屏幕,我们必须使用List容器
// 第二 我们要滑动删除新增功能,也需要这个功能
List({space:10}){
ForEach(
this.tasks,
(item: Task, index) => {
// List里面千万千万不可以直接写 Row(){} 必须用ListItem(){} 包裹着它,否则一定会报错。我遇到很多次了!!!
ListItem(){
Row(){
Text(item.name)
.fontSize(20)
// 这里我用来一个复选框
Checkbox()
// 默认值是False, finished: boolean = false 说明没有选中。 如果选中则修改默认值, 用布尔值去判断
.select(item.finished,)
// onchange 是人为的去做勾选, 或者取消勾选
.onChange(val => {
// 1.更新当前任务状态
item.finished = val
// 2. 更新已经完成函数的数量
// this.finishedTask = this.tasks.filter(item=>item.finished).length
// 上面这句省略了,增加函数的复用性, 专门写了个函数让我们来调用,功能和上面一样
this.handleTaskChange()
})
}
// 给予每一个新增任务1属性
.card()
// 修改每一个新增的任务卡片布局,让其每行在手机正中间
.justifyContent(FlexAlign.SpaceBetween)
}
// 在ListItem后面去跟一个函数,具体可以查官方文档
// 建议用局部函数, 因为我们要操作外面定义的数组,更方便
.swipeAction({end:this.DeleteButton(index)})
}
)
}
.width('100%')
//任务列表必须设置高度,否则没办法往下拉。 但不能写成.height('100%') 这样没有效果。
.layoutWeight(1)
// 让任务列表居中
.alignListItem(ListItemAlign.Center)
}
// 这是Column样式
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
最后一部分我们写最后一个功能,那就是删除按钮,也很重要的哈,向左划每个任务条,就能看到删除按钮,点击删除就好了, so easy!
@Builder DeleteButton(index:number){
Button(){
Image($r('app.media.return'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(()=>{
// 把角标对应的元素删掉
this.tasks.splice(index,1)
// 每删除一个任务, 发生变更,任务一旦发生变更,数组内容变更。 更新任务进程
this.handleTaskChange()
})
}
以上是每段代码的解析,我知道有些繁琐, 我接下来会把整个代码给大家,直接复制粘贴到编译器就可以实现了。
// 任务类
class Task{
static id: number = 1
// 任务名称
name: string = `任务${Task.id++}`
// 任务状态: 是否完成
finished: boolean = false
}
// 统一的卡片样式
@Styles function card(){
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({radius: 6, color:'#1F000000',offsetX:2,offsetY:4})
}
// 任务完成样式
@Extend(Text) function finishedTask(){
.decoration({type:TextDecorationType.LineThrough})
.fontColor('#B1B2B1')
}
@Entry
@Component
struct PropPage{
// 总任务数量
@State totalTask: number = 0
// 已完成任务数量
@State finishedTask: number = 0
// 任务数组
@State tasks: Task[] = []
// 任务修改时候触发的一个函数
handleTaskChange(){
// 2. 更新任务总数量
this.totalTask = this.tasks.length
// 2. 更新已经完成函数的数量
this.finishedTask = this.tasks.filter(item=>item.finished).length
}
build() {
Column({space:10}){
Row(){
Text('任务进程')
.fontSize(30)
.fontWeight(FontWeight.Bold)
// 现在我用这个容器 Stack(){.......} 将我的进度条以及这个百分比的进度值堆在一起, 这样进度条就和进度值重叠了。
Stack(){
// 进度条的写法是 Progress({.......}) 在这里我选的是环形进度条
Progress({
value:this.finishedTask,
total:this.totalTask,
type: ProgressType.Ring
})
.width(100)
// 因为我用了 .justifyContent(FlexAlign.SpaceEvenly) 这个属性,它是用于平均分配的。 假设
// 这里我不使用 Row() 再去把这个进度数字弄成一行,会导致百分比左右两边的数字隔的比较远。
Row(){
Text(this.finishedTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / '+this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({top:20,bottom:30})
.justifyContent(FlexAlign.SpaceEvenly)
// 2.新增任务按钮
Button('新增任务')
.width(200)
.onClick(()=>{
// 1. 新增任务数据
this.tasks.push(new Task())
// 2. 更新任务总数量
// this.totalTask = this.tasks.length
// 上面这句省略了,增加函数的复用性, 专门写了个函数让我们来调用,功能和上面一样
this.handleTaskChange()
})
// 3. 任务列表, 遍历每一个新增的任务
// 第一假如新增任务溢出屏幕,我们必须使用List容器
// 第二 我们要滑动删除新增功能,也需要这个功能
List({space:10}){
ForEach(
this.tasks,
(item: Task, index) => {
// List里面千万千万不可以直接写 Row(){} 必须用ListItem(){} 包裹着它,否则一定会报错。我遇到很多次了!!!
ListItem(){
Row(){
Text(item.name)
.fontSize(20)
// 这里我用来一个复选框
Checkbox()
// 默认值是False, finished: boolean = false 说明没有选中。 如果选中则修改默认值, 用布尔值去判断
.select(item.finished,)
// onchange 是人为的去做勾选, 或者取消勾选
.onChange(val => {
// 1.更新当前任务状态
item.finished = val
// 2. 更新已经完成函数的数量
// this.finishedTask = this.tasks.filter(item=>item.finished).length
// 上面这句省略了,增加函数的复用性, 专门写了个函数让我们来调用,功能和上面一样
this.handleTaskChange()
})
}
// 给予每一个新增任务1属性
.card()
// 修改每一个新增的任务卡片布局,让其每行在手机正中间
.justifyContent(FlexAlign.SpaceBetween)
}
// 在ListItem后面去跟一个函数,具体可以查官方文档
// 建议用局部函数, 因为我们要操作外面定义的数组,更方便
.swipeAction({end:this.DeleteButton(index)})
}
)
}
.width('100%')
//任务列表必须设置高度,否则没办法往下拉。 但不能写成.height('100%') 这样没有效果。
.layoutWeight(1)
// 让任务列表居中
.alignListItem(ListItemAlign.Center)
}
// 这是Column样式
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
@Builder DeleteButton(index:number){
Button(){
Image($r('app.media.return'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(()=>{
// 把角标对应的元素删掉
this.tasks.splice(index,1)
// 每删除一个任务, 发生变更,任务一旦发生变更,数组内容变更。 更新任务进程
this.handleTaskChange()
})
}
}
代码的注释我写的非常非常详细,不懂的童鞋要仔细看哈!!!
哦对了,这是我删除键引用的一个小图片,如果你懒的找话可以拿去用,命名为:return.png ,放在 app.media.retur 文件夹下面。
。

517

被折叠的 条评论
为什么被折叠?



