系列文章目录
目录
前言
作业清单在日常生活和工作中非常重要,一个高效的作业清单工具能帮助更好地管理任务,提高效率。在前几篇文章中,介绍了作业清单应用的概述、主页面设计、任务创建和编辑,以及关系型数据库的搭建。
本篇文章重点介绍作业清单的通用工具类,包括日志类、时间工具和媒体查询。
- 日志类:记录应用运行时的信息,如错误日志和调试信息,帮助定位和修复问题,并分析运行情况以优化性能。
- 时间工具:处理时间相关的功能,如获取当前时间、比较时间和格式化时间,提升应用的灵活性和可用性。
- 媒体查询:适应不同屏幕尺寸的设备,确保网页在各种设备上都有最佳用户体验。
一、关键技术
1.1 日志类
- 日志模块:使用日志库(如 `hilog`)来记录应用运行时的信息,包括错误日志、调试信息等。
- 日志级别:定义不同的日志级别(如 debug、info、warn、error),并实现相应的方法来记录不同级别的日志信息。
- 日志前缀和服务域:允许在日志记录时添加前缀和服务域,以便在日志中标识日志的来源。
- 模块化设计:将日志记录功能封装在独立的类中,便于日后维护和扩展。
- 日志输出配置:配置日志输出的格式和目标,如控制台输出、文件输出等。
1.2 时间工具
- 时间获取:提供获取当前时间的功能,支持多种时间格式。
- 时间比较:实现时间比较功能,便于任务的截止日期和当前时间进行比较。
- 时间格式化:提供将时间对象格式化为字符串的功能,支持多种格式(如 YYYY-MM-DD、HH:mm:ss 等)。
- 时间计算:实现时间的加减计算功能,如计算任务的剩余时间。
- 时区处理:处理不同地区的时区差异,确保时间的准确性和一致性。
1.3 媒体查询
- 媒体查询API:使用媒体查询 API(如 `mediaquery` 模块)监听媒体查询的变化,响应不同的屏幕尺寸和设备特性。
- 响应式设计:根据不同的媒体查询结果,调整页面布局和样式,适应小屏幕(sm)、中等屏幕(md)和大屏幕(lg)。
- 事件监听:实现媒体查询变化时的事件监听,调用相应的回调函数处理逻辑。
- 暗黑模式支持:通过媒体查询检测系统的暗黑模式设置,并相应调整应用的主题和样式。
- 自适应布局:利用 CSS 和 JavaScript 配合,实现页面在不同设备上的自适应布局。
二、示意图
三、日志类
Logger.ets
封装日志记录功能,支持不同级别的日志输出。
3.1 功能简介
- 提供了 debug、info、warn 和 error 四个方法,用于输出不同级别的日志信息。
- 可以指定日志的前缀和服务域,以便在日志中标识日志来源。
- 使用 hilog 模块实现日志输出,通过调用相应的方法将日志信息发送到系统日志记录器。
- 特点:
- 构造函数可以接受两个参数:prefix 用于标识日志的前缀,domain 表示服务域,其取值范围为 0x0 到 0xFFFFF。
- 提供了四个方法,分别对应不同的日志级别,使得可以根据需要输出不同级别的日志信息。
- 采用了模块化设计,将日志输出功能封装在独立的类中,便于日后维护和扩展。
3.2 代码文件
import hilog from '@ohos.hilog';
class Logger {
private domain: number;
private prefix: string;
private format: string = '%{public}s, %{public}s';
constructor(prefix: string = 'MyApp', domain: number = 0xFF00) {
this.prefix = prefix;
this.domain = domain;
}
debug(...args: string[]): void {
hilog.debug(this.domain, this.prefix, this.format, args);
}
info(...args: string[]): void {
hilog.info(this.domain, this.prefix, this.format, args);
}
warn(...args: string[]): void {
hilog.warn(this.domain, this.prefix, this.format, args);
}
error(...args: string[]): void {
hilog.error(this.domain, this.prefix, this.format, args);
}
}
export default new Logger('Rdb', 0xFF00)
四、时间工具
提供时间格式化、时间计算等功能。
DDLState.ets
DDL状态组件,显示DDL状态信息。
4.1 功能简介
- 实现了对待办事项进行按照紧急程度分类显示的功能,分为非常紧急、紧急、还有时间和该开始了四个分类。
- 提供了搜索功能,可以根据任务名称进行搜索并显示结果。
- 支持对任务进行编辑,包括勾选完成、修改截止日期等操作。
- 实现了点击待办事项后显示任务详情的功能,包括任务名称、截止日期等信息。
- 使用了 TaskTable 类来处理与任务数据相关的数据库操作,实现了对任务数据的增删改查功能。
- 通过 TaskListItemData 类来定义待办事项的数据结构,包括任务名称、截止日期等信息。
- 利用 Logger 类来记录日志信息,方便调试和错误排查。
- 使用了 CustomDialogController 和 TaskItemDialog_ViewOnly 来实现任务详情的弹窗显示功能。
- 采用 OhOS 提供的 UI 组件和布局方式,实现了待办事项的分类显示和搜索功能。
4.2 代码文件
@Component
export default struct DDLState {
@Link tasks: Array<TaskListItemData>
@Link categoryList: TaskCategoryData[]
@State isEditing: boolean = false
@State dialogIsAddNew: boolean = true
@State taskItem: TaskListItemData = new TaskListItemData()
private taskTable: TaskTable = new TaskTable(() => {});
private dialogSelectedIndex: number = -1
dialogController_view: CustomDialogController = new CustomDialogController({
builder: TaskItemDialog_ViewOnly({
taskItem: $taskItem,
categoryList: $categoryList
}),
alignment: DialogAlignment.Bottom,
customStyle: true
})
@Builder TaskList_ListItem(item: TaskListItemData) {
Column() {
Row() {
Row() {
if (!this.isEditing) {
Checkbox()
.select(item.is_completed)
.onChange((value: boolean) => {
animateTo({duration: 300, curve: Curve.EaseInOut}, () => {
item.is_completed = value
this.updateExistingTask(item)
})
})
.margin({ right: 10 })
}
Text(item.task_name)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(1)
.width('60%')
}
Row() {
Column() {
Text(getDateString(item.due_date_stamp))
.fontSize(16)
Text(getTimeString(item.due_date_stamp))
.fontSize(13)
}.alignItems(HorizontalAlign.End)
.margin({ right: 10 })
if (!item.is_completed) Button({ type: ButtonType.Circle, }) {
Text(' ')
}
.backgroundColor(CommonConstants.DDL_COLOR[item.getDDLState()])
.height(12)
.width(12)
}
}.justifyContent(FlexAlign.SpaceBetween)
.height(56)
.width('100%')
.padding({ left: 12, right: 12 })
Progress({value: 100 - item.getDDLPer()})
.margin({bottom: 10})
.color(CommonConstants.DDL_COLOR[item.getDDLState()])
}
}
@Builder TaskList_DDLState(text: string, state: string) {
Text(text)
.fontSize(20)
.width('100%')
.margin({ bottom: 10, top: 20})
.textAlign(TextAlign.Start)
.padding({ left: 12, right: 12 })
List() {
ForEach(this.tasks, (item: TaskListItemData) => {
if (!item.is_completed && item.getDDLState() == state) ListItem() {
this.TaskList_ListItem(item)
}.width('100%')
.backgroundColor(0xffffff)
.onClick(() => {
this.taskItem = item
this.dialogController_view.open()
})
})
}
.width('100%')
.borderRadius(20)
.divider({ strokeWidth: 1 })
.margin({ bottom: 20 })
}
updateExistingTask(taskData: TaskListItemData) {
this.taskTable.updateData(taskData, () => {})
let new_task = this.tasks
this.tasks = []
new_task[this.dialogSelectedIndex] = taskData
this.tasks = new_task // 触发 UI 刷新
this.dialogSelectedIndex = -1
}
querySearchTask(searchVal: string, callback?: Function) {
this.taskTable.queryTaskName(`%${searchVal}%`, (searchRes) => {
this.tasks = []
searchRes.forEach(item => {this.tasks.push(item)})
for (let i = 0; i < this.tasks.length; ++i) {
this.tasks[i].setAll(this.categoryList)
}
if(callback !== undefined) callback()
}, (searchVal == ''))
}
build() {
Column() {
Stack({alignContent: Alignment.Bottom}) {
Navigation() { // UI 标题栏
// UI 搜索
if (!this.isEditing) Search()
// .onClick(() => { this.isOnSearch = true})
.onSubmit((value: string) => {
this.querySearchTask(value)
})
// .padding({ left: 12, right: 12 })
.width('90%')
Column() {
// UI 待办事项界面
Scroll() {
Column() {
// UI 待办事项列表
this.TaskList_DDLState('非常紧急', 'critical')
this.TaskList_DDLState('紧急', 'hard')
this.TaskList_DDLState('还有时间', 'medium')
this.TaskList_DDLState('该开始了', 'easy')
}
.padding({ left: 12, right: 12, bottom: 10, top: 10 })
.margin({bottom: 40})
// .height('70%')
.justifyContent(FlexAlign.Start)
}.edgeEffect(EdgeEffect.Spring)
.scrollBar(BarState.Off)
}
.justifyContent(FlexAlign.SpaceBetween)
}
.height('100%')
.width('100%')
.titleMode(NavigationTitleMode.Mini)
.hideBackButton(true)
.mode(NavigationMode.Stack)
.title('截止时间')
}.height('100%')
}.width('100%')
.height('100%')
}
}
function getDateString(date_stamp: number): string {
let date: Date = new Date()
date.setTime(date_stamp)
Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleDateString()}`)
let ds: string[] = date.toLocaleDateString().split('/')
let res: string = `${ds[2]}/${ds[0]}/${ds[1]}`
return res
}
function getTimeString(date_stamp: number): string {
let date: Date = new Date()
date.setTime(date_stamp)
Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleTimeString()}`)
return date.toLocaleTimeString()
}
五、媒体查询工具类
MediaQuery.ets
媒体查询工具类,提供媒体查询功能,用于检测不同设备尺寸和暗模式的变化。
5.1 功能简介
- 通过 mediaquery 模块监听媒体查询的变化,包括屏幕宽度和暗黑模式等。
- 根据不同的媒体查询结果,确定当前屏幕的类型,包括小屏幕(sm)、中等屏幕(md)和大屏幕(lg)。
- 提供了对应于不同屏幕类型的回调函数,用于处理屏幕类型变化时的逻辑。
- 使用了 mediaquery 模块提供的 matchMediaSync 方法来进行媒体查询的同步匹配。
- 使用了 on 方法来监听媒体查询结果的变化,并在变化时调用相应的回调函数处理。
- 通过 console.info 方法打印出当前屏幕类型,方便调试和查看。
- 通过 screenType 属性记录当前屏幕类型,方便其他模块或组件根据屏幕类型进行适配。
5.2 代码文件
import mediaquery from '@ohos.mediaquery';
import deviceInfo from '@ohos.deviceInfo';
class MediaQuery {
smListener = mediaquery.matchMediaSync('(width < ' + 520 + 'vp)');
mdListener = mediaquery.matchMediaSync('(width >= ' + 520 + 'vp) and (width <= ' + 840 + 'vp)');
lgListener = mediaquery.matchMediaSync('(width > ' + 840 + 'vp)');
darkmodeListener = mediaquery.matchMediaSync('screen and (dark-mode: true)');
portraitFuncSm = null;
portraitFuncMd = null;
portraitFuncLg = null;
portraitFuncDarkmode = null;
screenType: string = ''
constructor() {
var that = this;
this.smListener = mediaquery.matchMediaSync('(width <= ' + 672 + ')');
this.mdListener = mediaquery.matchMediaSync('(width > ' + 672 + ') and (width <= ' + 1250 + ')');
this.lgListener = mediaquery.matchMediaSync('(width > ' + 1250 + ')');
this.darkmodeListener = mediaquery.matchMediaSync('screen and (dark-mode: true)');
this.portraitFuncSm = this.onPortraitSm.bind(this)
this.smListener.on('change', this.portraitFuncSm)
this.portraitFuncMd = this.onPortraitMd.bind(this)
this.mdListener.on('change', this.portraitFuncMd)
this.portraitFuncLg = this.onPortraitLg.bind(this)
this.lgListener.on('change', this.portraitFuncLg)
}
public onPortraitSm(mediaQueryResult) {
if (mediaQueryResult.matches) {
this.screenType = 'sm'
console.info('sm')
}
}
public onPortraitMd(mediaQueryResult) {
if (mediaQueryResult.matches) {
this.screenType = 'md'
console.info('md')
}
}
public onPortraitLg(mediaQueryResult) {
if (mediaQueryResult.matches) {
this.screenType = 'lg'
console.info('lg')
}
}
}
export default new MediaQuery()
六、遇到的问题及解决方案
6.1 任务列表 UI 不更新
问题描述: 在更新任务状态(如完成任务)后,任务列表的 UI 有时不会自动刷新,导致用户看不到最新的任务状态。
解决方案:
通过重新分配 `tasks` 数组来触发 UI 刷新。在更新任务数据后,将 `tasks` 数组置为空,再将更新后的任务数组重新赋值给 `tasks`。
updateExistingTask(taskData: TaskListItemData) {
this.taskTable.updateData(taskData, () => {})
let new_task = this.tasks
this.tasks = []
new_task[this.dialogSelectedIndex] = taskData
this.tasks = new_task // 触发 UI 刷新
this.dialogSelectedIndex = -1
}
6.2 搜索功能不工作
问题描述: 在使用搜索功能时,无法正确过滤和显示符合条件的任务。
解决方案:
确保在查询任务名称时,使用了正确的 SQL 通配符,并将搜索结果正确地赋值给 `tasks` 数组。
querySearchTask(searchVal: string, callback?: Function) {
this.taskTable.queryTaskName(`%${searchVal}%`, (searchRes) => {
this.tasks = []
searchRes.forEach(item => { this.tasks.push(item) })
for (let i = 0; i < this.tasks.length; ++i) {
this.tasks[i].setAll(this.categoryList)
}
if (callback !== undefined) callback()
}, (searchVal == ''))
}
6.3 日志信息不完整
问题描述: 日志记录的信息不够详细,无法提供足够的调试和错误排查信息。
解决方案:
增强日志记录的详细程度,特别是在关键操作和方法调用时添加日志。
使用 `Logger` 类在关键步骤中记录详细的调试信息。
function getDateString(date_stamp: number): string {
let date: Date = new Date()
date.setTime(date_stamp)
Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleDateString()}`)
let ds: string[] = date.toLocaleDateString().split('/')
let res: string = `${ds[2]}/${ds[0]}/${ds[1]}`
return res
}
function getTimeString(date_stamp: number): string {
let date: Date = new Date()
date.setTime(date_stamp)
Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleTimeString()}`)
return date.toLocaleTimeString()
}
总结
通过合理使用日志类、时间工具和媒体查询这些关键技术,可以极大地提升任务管理应用的性能和用户体验。日志类为我们提供了详细的运行信息和调试支持,时间工具让我们可以灵活处理各种时间相关操作,而媒体查询确保了应用的响应性和自适应布局。这些技术的结合,使得我们的任务管理应用不仅功能强大,而且易于维护和扩展。
标签:tasks,date,string,item,HarmonyOS,期末,清单,new,日志 From: https://blog.csdn.net/Ababx/article/details/139814608