赞
踩
环境:OpenHarmony 4.0
任务列表应用,基于OpenHarmony 4.0开发,主要功能:任务列表增删改查,任务进度显示,后台通知提醒
main ├─ets │ ├─component // 自定义组件 │ │ TaskDialog.ets // 自定义添加/修改弹窗 │ │ TaskKeyboard.ets │ │ TaskListItem.ets // 自定义ListItem组件 │ │ TaskProgress.ets // 进度展示 │ │ │ ├─entryability // 程序入口 │ │ EntryAbility.ets │ │ │ ├─pages │ │ DetailsPage.ets │ │ TaskPage.ets // 主页 │ │ │ ├─pojo // 实体类 │ │ │ Task.ets │ │ │ TaskMenuItem.ets │ │ │ │ │ └─dto // 增强实体类 │ │ TaskDto.ets │ │ │ ├─service │ │ TaskReminderService.ets // 后台提醒提醒工具类 │ │ │ └─utils // 工具类 │ FileManager.ets │ NotificationUtil.ets │ PreferencesUtil.ets │ RDBUtil.ets │ TransferToUtil.ets │ └─resources // 资源目录
需要权限: PUBLISH_AGENT_REMINDER
应用入口界面,在生命周期aboutToAppear中创建/连接数据库 ‘Task’ ,同时查询数据库中所有数据,为数组赋值。使用List组件遍历数组,实现任务列表的呈现。在自定义Menu组件中提供筛选分类功能,根据onClick()点击事件重新查询对应分类数据并赋值。
import font from '@ohos.font' import relationalStore from '@ohos.data.relationalStore' import { AddTaskDialog, EditTaskDialog } from '../component/TaskDialog' import { TaskListItem } from '../component/TaskListItem' import { TaskProgress } from '../component/TaskProgress' import { rdbUtil } from '../utils/RDBUtil' import TaskDto from '../pojo/dto/TaskDto' import TaskMenuItem from '../pojo/TaskMenuItem' import router from '@ohos.router' import { taskReminderService } from '../service/TaskReminderService' @Entry @Component struct TaskPage { @Provide arr: TaskDto[] = [] @Provide progress: number = 0 @State index: number = -1 @State isChecked: boolean = false @State menuItems: TaskMenuItem[] = [new TaskMenuItem('全部', '#ffffd88b', true), new TaskMenuItem('待完成', '#ffff', false), new TaskMenuItem('已完成', '#ffff', false)] @State menuIndex: number = 0 addTaskDialogController: CustomDialogController = new CustomDialogController({ builder: AddTaskDialog() }) editTaskDialogController: CustomDialogController = new CustomDialogController({ builder: EditTaskDialog({index: this.index}) }) build() { Column() { Row() { Text('任务进度:').fontSize(30).fontWeight(FontWeight.Bold).fontFamily('02').margin({ left: 10 }) TaskProgress().margin({ right: 40 }).id('TaskProgress') } .backgroundColor('#ffff') .borderRadius(20) .width('90%') .height('20%') .justifyContent(FlexAlign.SpaceBetween) .margin({ top: 20 }) Row() { Button('添加任务').margin({ left: 10 }) .onClick(() => { this.addTaskDialogController.open() }) Text('全选').fontSize(17).fontWeight(FontWeight.Bold).margin({ left: '45%' }) Checkbox().width(15).onChange((flag: boolean) => { this.isChecked = flag }) Image($r('app.media.screen')).width(30).bindMenu(this.filter_Menu()) }.width('90%').height('5%').margin({ top: 20 }) List({ space: 10 }) { ForEach(this.arr, (item: TaskDto, index: number) => { ListItem() { TaskListItem({ taskDto: this.arr[index], isChecked: this.isChecked}) }.swipeAction({ start: { builder: this.taskListItem_Menu(index) } }) }) }.width('90%').height('65%').margin({ top: 20 }) }.width('100%').backgroundColor('#ffe9e6e6').justifyContent(FlexAlign.Center) } // 生命周期 初始化数据 async aboutToAppear() { // 注册字体 font.registerFont({ familyName: '01', familySrc: $rawfile('font/media.ttf') }) font.registerFont({ familyName: '02', familySrc: $rawfile('font/02.ttf') }) font.registerFont({ familyName: '03', familySrc: $rawfile('font/YanZhenQingDuoBaoTaBei-2.ttf') }) await rdbUtil.createRDB('Task').then((rdb) => { rdb.executeSql('create table if not exists Task(id integer primary key autoincrement, title string, content string, date string, reminderId integer, state boolean, isExpand boolean)') }) let pre = new relationalStore.RdbPredicates('Task') this.arr = await rdbUtil.queryArray <TaskDto> (pre) this.progress = this.getProgress() } // 获取数据 getData() { let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('Task') switch (this.menuIndex) { case 0: predicates.orderByAsc('state').orderByDesc('id') rdbUtil.queryArray <TaskDto> (predicates).then((value: TaskDto[]) => { this.arr = value }) return case 1: predicates.equalTo('state', '0') rdbUtil.queryArray <TaskDto> (predicates).then((value: TaskDto[]) => { this.arr = value }) return case 2: predicates.equalTo('state', '1') rdbUtil.queryArray <TaskDto> (predicates).then((value: TaskDto[]) => { this.arr = value }) return } } // 获取当前完成任务数 getProgress() : number { let num: number = 0 for (let item of this.arr) { if (item.state == '1') { num++ } } return num } // 自定义组件 ListItemMenu @Builder taskListItem_Menu(index: number) { Row({space: 2}) { Image($r('app.media.edit03')).width(30).onClick(() => { this.index = index this.editTaskDialogController.open() // router.pushUrl({ // url: 'pages/DetailsPage', // params: this.arr[index] // }).then(() => { // this.getData() // }) }) Image($r('app.media.delete03')).width(30).onClick(() => { rdbUtil.deleteById('Task', this.arr[index].id) // taskReminderService this.getData() }) }.width(65) } // 自定义组件 过滤菜单 @Builder filter_Menu() { Menu() { ForEach(this.menuItems, (item: TaskMenuItem, index: number) => { MenuItem({content: item.itemContent}).selected(item.isSelected).backgroundColor(item.isSelected ? '#ffffd88b' : '#ffff').onClick(() => { this.menuItems.forEach((it: TaskMenuItem, i: number) => { if (i == index) { it.isSelected = true } else { it.isSelected = false } }) this.menuIndex = index this.getData() }) }) } } }
ListItem组件实现复选框勾选完成,展开详细信息功能
import { Driver } from '@ohos.UiTest' import TaskDto from '../pojo/dto/TaskDto' import Task from '../pojo/Task' import { rdbUtil } from '../utils/RDBUtil' @Component export struct TaskListItem { @State isSelected: boolean = false @State isExpand: boolean = false @Consume progress: number @Link isChecked: boolean @ObjectLink taskDto: TaskDto aboutToAppear() { this.isSelected = (this.taskDto.state == '0') ? false : true this.isExpand = (this.taskDto.isExpand == '1') } build() { Column() { Row() { Text(this.taskDto.title) .fontSize(20) .fontWeight(FontWeight.Bold) .fontColor(this.isSelected ? '#ffa7a2a2' : '#ff000000') .decoration({type: this.isSelected ? TextDecorationType.LineThrough : TextDecorationType.None, color: '#ffff008f'}) .maxLines(1).width('90%') Checkbox().select(this.isChecked ? true : this.isSelected).width(15).onChange((flag) => { this.taskDto.state = flag ? '1' : '0' this.isSelected = !this.isSelected if (!flag) { this.isChecked = false this.progress -- } else { this.progress ++ } rdbUtil.updateById <TaskDto> ('Task', this.taskDto.id, this.taskDto) }) Image($r('app.media.expand02')).width(20).rotate({angle: this.isExpand ? 0 : -90}).margin({left: 2}) .onClick(() => { this.isExpand = !this.isExpand this.taskDto.isExpand = this.isExpand ? '1' : '0' rdbUtil.updateById <TaskDto> ('Task', this.taskDto.id, this.taskDto) }) }.width('95%').height(50).padding(10) if (this.isExpand) { Text(this.taskDto.content).fontSize(16.5).fontFamily('03').width('90%') Text(new Date(this.taskDto.date).toLocaleString()).fontSize(14).fontStyle(FontStyle.Italic).fontColor('#ff835ff5').opacity(0.3).textAlign(TextAlign.End).width('90%') } }.backgroundColor('#ffff').borderRadius(20).width('100%') } }
获取父组件传入的进度,在环形进度条实时显示
import TaskDto from '../pojo/dto/TaskDto' @Component export struct TaskProgress { @Consume arr: TaskDto[] @Consume progress: number // getProgress() : number { // let num: number = 0 // for (let item of this.arr) { // if (item.state == '1') { // num++ // } // } // return num // } build() { Stack() { Progress({value: this.progress, total: this.arr.length, type: ProgressType.Ring}) .width(100) .color('#ff60b1e9') .backgroundColor('#ffe75b82') .style({status: ProgressStatus.PROGRESSING, enableSmoothEffect: true}) Text() { Span(this.progress.toString()) Span('/') Span(this.arr.length.toString()) }.fontSize(25) } } }
在 CustomDialog 中获取当前数组,并通过 RdbUtil 在数据库内插入、修改数据,实现数据持久化。同时调起 TaskReminderService 实现后台代理提醒。
import TaskDto from '../pojo/dto/TaskDto' import Task from '../pojo/Task' import { taskReminderService, TaskReminderService } from '../service/TaskReminderService' import { rdbUtil } from '../utils/RDBUtil' // 添加弹窗 @CustomDialog export struct AddTaskDialog { @State dialogSize: number = 200 @State areaSize: number = 100 @State isExpand: boolean = false @Consume arr: TaskDto[] addTaskDialogController: CustomDialogController title: string = '' content: string = '' date: Date = new Date() build() { Column() { Row() { Image($r('app.media.expand01')) .width(15) .onClick(() => { if (this.isExpand) { animateTo({ duration: 400, curve: Curve.Linear }, () => { this.dialogSize = 200 this.areaSize = 100 }) this.isExpand = !this.isExpand } else { animateTo({ duration: 400, curve: Curve.Linear }, () => { this.dialogSize = 420 this.areaSize = 200 }) this.isExpand = !this.isExpand } }) }.justifyContent(FlexAlign.End).width('90%').height(15).margin({top: 5}) if (this.isExpand) { TextInput({text: this.title, placeholder: '请输入标题'}).height(40).width('90%').margin({top: '3%'}) .onChange((value: string) => { this.title = value }) } TextArea({text: this.content, placeholder: '请输入任务内容'}).height(this.areaSize).width('90%').margin({top: '3%'}) .onChange((value: string) => { this.content = value }) if (this.isExpand) { Button('设置提醒日期', {type: ButtonType.Normal}).height(40).margin({top: 20}).backgroundColor('#ff48cdc1').onClick(() => { DatePickerDialog.show({ start: new Date("2000-1-1"), end: new Date("2100-12-31"), selected: this.date, showTime:true, useMilitaryTime:false, disappearTextStyle: {color: '#ffbfbfbf', font: {size: '22fp', weight: FontWeight.Bold}}, textStyle: {color: '#ffbfbfbf', font: {size: '18fp', weight: FontWeight.Normal}}, selectedTextStyle: {color: '#ff583db7', font: {size: '14fp', weight: FontWeight.Regular}}, onDateAccept: (date: Date) => { this.date = date console.log(this.date.toString()); } }) }) } Row() { // 取消Button Button('cancel').onClick(() => { AlertDialog.show({ title: '警告', message: '取消将丢失所有内容', autoCancel: false, alignment: DialogAlignment.Center, primaryButton: { value: '取消', action: () => {} }, secondaryButton: { value: '确认', action: () => { this.addTaskDialogController.close() } } }) }) // 确认Button 插入数据到RDB Button('confirm').onClick(() => { let task: Task task = this.isExpand ? new Task(this.title, this.content, this.date.toString()) : new Task('Task未命名' , this.content, new Date().toString()) console.log(JSON.stringify(task)) rdbUtil.insert <Task> ('Task', task).then(async (num) => { let taskDto = await rdbUtil.queryById <TaskDto> ('Task', num) this.arr.push(taskDto) // 相同 notificationID 的通知会覆盖 taskReminderService.init(taskDto.id, taskDto.title, taskDto.date) taskReminderService.publish((reminderId: number) => { task.reminderId = reminderId rdbUtil.updateById <Task> ('Task', taskDto.id, task) }) }) this.addTaskDialogController.close() }) } .width('80%') .justifyContent(FlexAlign.SpaceBetween) .margin({top: 15}) } .height(this.dialogSize) .justifyContent(FlexAlign.Start) } } // 编辑弹窗 @CustomDialog export struct EditTaskDialog { @Consume arr: TaskDto[] @Prop index: number = -1 @State title: string = '' @State content: string = '' @State date: Date = new Date() editTaskDialogController : CustomDialogController aboutToAppear() { let taskDto: TaskDto = this.arr[this.index] this.title = taskDto.title this.content = taskDto.content this.date = new Date(taskDto.date) } build() { Column() { TextInput({text: this.title, placeholder: '请输入标题'}).height(40).width('90%').margin({top: '3%'}) .onChange((value: string) => { this.title = value }) TextArea({text: this.content, placeholder: '请输入任务内容'}).height(200).width('90%').margin({top: '3%'}) .onChange((value: string) => { this.content = value }) Button('设置提醒日期', {type: ButtonType.Normal}).height(40).margin({top: 20}).backgroundColor('#ff48cdc1').onClick(() => { DatePickerDialog.show({ start: new Date("2000-1-1"), end: new Date("2100-12-31"), selected: this.date, showTime:true, useMilitaryTime:false, disappearTextStyle: {color: '#ffbfbfbf', font: {size: '22fp', weight: FontWeight.Bold}}, textStyle: {color: '#ffbfbfbf', font: {size: '18fp', weight: FontWeight.Normal}}, selectedTextStyle: {color: '#ff583db7', font: {size: '14fp', weight: FontWeight.Regular}}, onDateAccept: (date: Date) => { this.date = date } }) }) Row() { // 取消Button Button('cancel').onClick(() => { AlertDialog.show({ title: '警告', message: '取消将丢失所有内容', autoCancel: false, alignment: DialogAlignment.Center, primaryButton: { value: '取消', action: () => {} }, secondaryButton: { value: '确认', action: () => { this.editTaskDialogController.close() } } }) }) // 确认Button 更新数据到RDB Button('confirm').onClick(() => { let task: Task = new Task(this.title, this.content, this.date.toString()) let id: number = this.arr[this.index].id rdbUtil.updateById <Task> ('Task', id, task).then(async (num) => { let taskDto = await rdbUtil.queryById <TaskDto> ('Task', id) this.arr[this.index] = taskDto // 相同 notificationID 的通知会覆盖 taskReminderService.init(taskDto.id, taskDto.title, taskDto.date) taskReminderService.publish((reminderId: number) => { task.reminderId = reminderId rdbUtil.updateById <Task> ('Task', taskDto.id, task) }) }) this.editTaskDialogController.close() }) } .width('80%') .justifyContent(FlexAlign.SpaceBetween) .margin({top: 15}) } .height(420) .justifyContent(FlexAlign.Start) } }
发送日历类型后台代理提醒
import reminderAgentManager from '@ohos.reminderAgentManager' import { BusinessError, Callback } from '@ohos.base' const TAG = '[TaskReminderService]' export class TaskReminderService { timer: reminderAgentManager.ReminderRequestCalendar = { reminderType: 1, actionButton: [ {title: '忽略', type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE}, {title: '延时', type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE} ], title: '[Task]', dateTime: this.str2DateTime(new Date().toLocaleString()) } init (id: number, content: string, dateTime: string) { this.timer.notificationId = id this.timer.content = content this.timer.dateTime = this.str2DateTime(dateTime) } publish (callback: Callback<number>) { try { reminderAgentManager.publishReminder(this.timer, (err: BusinessError, reminderId: number) => { if (err) { console.error(TAG, ` (publish) ERROR => ${JSON.stringify(err)}`) } else { console.info(TAG, ` (publish) SUCCESS => ${reminderId}`) callback(reminderId) } }) } catch (error) { console.error(TAG, ` (publish) ERROR => ${JSON.stringify(error as BusinessError)}`) } } cancel(id: number) { reminderAgentManager.getValidReminders() } private str2DateTime(str: string): reminderAgentManager.LocalDateTime { let date = new Date(str) let datetime: reminderAgentManager.LocalDateTime = { year: date.getFullYear(), // 注意: getMonth 返回 => month - 1 month: date.getMonth() + 1, day: date.getDate(), hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds() } return datetime } } export let taskReminderService = new TaskReminderService()
Task
@Observed export default class Task { title: string content: string date: string reminderId: number = -1 state: boolean | string = false isExpand: boolean | string = false constructor(title : string , content : string , date : string, reminderId ?: number, state ?: boolean | string) { this.title = title this.content = content this.date = date if (reminderId) { this.reminderId = reminderId } if (state) { this.state = state } } }
TaskDto
import Task from '../Task' @Observed export default class TaskDto extends Task { id: number constructor(id: number, title : string , content : string , date : string, reminderId ?: number, state ?: boolean | string) { super(title, content, date, (reminderId ? reminderId : -1)) this.id = id this.title = title this.content = content this.date = date if (state) { this.state = state } } }
TaskMenuItem
@Observed
export default class TaskMenuItem {
itemContent: string
bgColor: string
isSelected: boolean
constructor(itemContent: string, bgColor: string, isSelected: boolean) {
this.itemContent = itemContent
this.bgColor = bgColor
this.isSelected = isSelected
}
}
该代码仅为应用开发示例,功能并不完善。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。