电子说
本篇Codelab基于用户首选项,实现了备忘录新增、更新、删除以及查找等功能。效果如图所示:
完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:
gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md
]本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。
├──entry/src/main/ets // 代码区
│ ├──common
│ │ ├──constants
│ │ │ ├──CommonConstants.ets // 常量类
│ │ │ └──StyleConstants.ets // 样式常量类
│ │ └──utils
│ │ ├──Format.ets // 日期格式化函数
│ │ └──Logger.ets // 日志打印类
│ ├──entryability
│ │ └──EntryAbility.ts // 程序入口类
│ ├──model
│ │ └──NotesDataModel.ets // 备忘录方法类
│ ├──pages
│ │ ├──NoteHomePage.ets // 备忘录主页面(列表页)
│ │ └──NotesDetail.ets // 备忘录详情页
│ ├──view
│ │ ├──BottomBar.ets // 备忘录编辑页底部栏
│ │ ├──ConfirmDialog.ets // 自定义弹窗
│ │ └──MemoItem.ets // 自定义备忘录列表组件
│ └──viewmodel
│ └──NotesInfoViewModel.ets // 备忘录默认数据实体
└──entry/src/main/resources // 资源文件目录
在这个章节中,需要实现备忘录数据的初始化,并且通过List组件将其渲染出来。效果如图所示:
在saveDefaultData方法中先通过getPreferences方法获取preferences实例,然后调用has方法查找数据库中是否存在“noteIdArr”这个key值,如果不存在调用实例的put方法将noteIdArr以及备忘录数据写入,最后通过flush方法进行数据持久化。
// NotesDataModel.ets
import dataStorage from '@ohos.data.preferences';
...
class NotesDataModel {
private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
/**
* 写入备忘录数据.
*/
async saveDefaultData() {
try {
let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME);
let isExist = await preferences.has(CommonConstants.PREFERENCE_NOTE_KEY);
if (!isExist) {
preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(noteIdArray));
preferences.flush();
notesItemArr.forEach((item: NotesInfoBean) = > {
let notes: NotesInfoBean = item;
let res = preferences.put(item.noteId, JSON.stringify(notes));
preferences.flush();
res.then(() = > {
Logger.info('Put the value successfully.' + item.noteId);
}).catch((err: Error) = > {
Logger.error(`Put the value failed with err: ${err}`);
})
})
}
} catch (err) {
Logger.error(`Failed to get preferences. Error = ${err}`);
}
}
/**
* 基于笔记类型获取对应备忘录数据.
*
* @param flag the folder type.
* @param allNotes all of notes.
* @returns subNotes.
*/
getSelectNotes(flag: FolderType, allNotes: Array< NotesInfoBean >): Array< NotesInfoBean > {
return allNotes.filter((item: NotesInfoBean) = > item.folder === flag);
}
}
在NoteHomePage.ets文件中调用saveDefaultData函数先将本地数据写入数据库,再调用实例的get方法进行查询操作。
// NoteHomePage.ets
import dataStorage from '@ohos.data.preferences';
...
@Entry
@Component
struct NoteHomePage {
@State folderType: Resource = $r('app.string.notes_all');
@State allNotes: Array< NotesInfoBean > = [];
@State selectNotes: Array< NotesInfoBean > = this.allNotes.sort();
private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
...
build() {
Column() {
...
List({ space: StyleConstants.MEMO_LIST_SPACE }) {
ForEach(this.selectNotes, (item: NotesInfoBean) = > {
ListItem() {
MemoItem({ noteItem: item })
}
}, (item: NotesInfoBean) = > JSON.stringify(item))
}
.margin({ top: $r('app.float.list_container_margin') })
.height(StyleConstants.NOTE_CONTENT_HEIGHT)
.width(StyleConstants.FULL_WIDTH)
}
.backgroundColor($r('app.color.page_background'))
.height(StyleConstants.FULL_HEIGHT)
}
onPageShow() {
this.getAllNotes();
}
async getAllNotes() {
await NotesDataModel.saveDefaultData();
try {
let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME);
let noteIds = await preferences.get(CommonConstants.PREFERENCE_NOTE_KEY, '');
while (this.allNotes.length >= 1) {
this.allNotes.pop();
}
JSON.parse(noteIds.toString()).forEach(async (item: NotesInfoBean) = > {
let note = await preferences.get(item.noteId, '');
this.allNotes.push(JSON.parse(note.toString()));
})
} catch (err) {
Logger.error('Get the value of noteIdArr failed with err:', err);
}
}
}
此章节介绍新增备忘录功能,点击列表页右上角加号进入编辑页,支持输入标题、备忘录内容以及添加图片。效果如图所示:
首先在列表页NoteHomePage.ets中添加跳转逻辑,设置路由参数params,其中operationType字段代表此次操作是新增还是修改。
// NoteHomePage.ets
Navigator({ target: 'pages/NotesDetail', type: NavigationType.Replace }) {
Row() {
Image($rawfile('ic_title_add.svg'))
...
}
.margin({ right: $r('app.float.note_add_margin') })
}
.params({
notesInfo: {
'noteId': new Date().getTime().toString(),
'title': '',
'folder': FolderType.Personal,
'content': '',
'imageArr': [],
'time': new Date().toTimeString().split(' ')[0],
'isFavorite': false
},
operationType: CommonConstants.ADD_NOTE
})
进入编辑页NotesDetail.ets后可以输入标题、内容以及选择对应的笔记类型等,确认保存后备忘录数据实时更新。
// NotesDetail.ets
build() {
...
TextInput({
text: this.notesInfo.title != '' ? this.notesInfo.title : '',
placeholder: this.notesInfo.title != '' ? '' : $r('app.string.note_title_placeholder')
})
...
.onChange((value: string) = > {
if (value !== this.notesInfo.title) {
this.notesInfo.title = value;
this.isDataChanged = true;
}
})
...
TextArea({
text: this.notesInfo.content !== '' ? this.notesInfo.content : '',
placeholder: this.notesInfo.content !== '' ? '' : $r('app.string.note_content_placeholder')
})
.onChange((value: string) = > {
if (value !== this.notesInfo.content) {
this.notesInfo.content = value;
this.isDataChanged = true;
}
})
...
}
onBackPress() {
if (this.isDataChanged || this.notesFolder !== this.notesInfo.folder || this.isCollectChange) {
this.saveDialogController.open();
} else {
router.replaceUrl({
url: 'pages/NoteHomePage'
});
}
return true;
}
// ConfirmDialog.ets
if (this.type === CommonConstants.SAVE_DIALOG) {
this.confirm = async () = > {
let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME);
// 保存备忘录数据实时更新
if (this.operationType === CommonConstants.ADD_NOTE) {
this.noteIdArray.push(new NoteIdBean(this.notesInfo.noteId));
preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(this.noteIdArray));
preferences.flush();
}
let newNotes = this.notesInfo;
await preferences.put(this.notesInfo.noteId, JSON.stringify(newNotes));
await preferences.flush();
router.replaceUrl({
url: 'pages/NoteHomePage'
});
}
}
此章节介绍更新数据库操作,与新增备忘录逻辑类似。效果如图所示:
首先在NotesDetail.ets中设置isDataChange和isCollectChange属性,来表示对应noteId的备忘录数据是否已更改。如果isDataChange或者isCollectChange为true表示已更改,在返回列表页时会拉起确认弹窗,确认保存后执行put方法去更改备忘录数据。
// NotesDetail.ets
build() {
Column() {
...
Stack({ alignContent: Alignment.Bottom }) {
Scroll(this.scroller) {
Column() {
TextInput({
text: this.notesInfo.title != '' ? this.notesInfo.title : '',
placeholder: this.notesInfo.title != '' ? '' : $r('app.string.note_title_placeholder')
})
...
.onChange((value: string) = > {
if (value !== this.notesInfo.title) {
this.notesInfo.title = value;
this.isDataChanged = true;
}
})
...
TextArea({
text: this.notesInfo.content !== '' ? this.notesInfo.content : '',
placeholder: this.notesInfo.content !== '' ? '' : $r('app.string.note_content_placeholder')
})
.onChange((value: string) = > {
if (value !== this.notesInfo.content) {
this.notesInfo.content = value;
this.isDataChanged = true;
}
})
...
}
}
...
BottomBar({
imageArr: $imageArr,
notesInfo: $notesInfo,
operationType: $operationType,
noteIdArray: $noteIdArray,
isDataChanged: $isDataChanged
})
}
...
}
.height(StyleConstants.FULL_HEIGHT)
.backgroundColor($r('app.color.white_color'))
}
...
onBackPress() {
if (this.isDataChanged || this.notesFolder !== this.notesInfo.folder || this.isCollectChange) {
this.saveDialogController.open();
} else {
router.replaceUrl({
url: 'pages/NoteHomePage'
});
}
return true;
}
// BottomBar.ets
// 点击收藏
this.clickCollect = () = > {
this.notesInfo.isFavorite = !this.notesInfo.isFavorite;
this.isFavorite = !this.isFavorite;
this.collectImgSrc = this.notesInfo.isFavorite ?
'ic_bottom_star_selected.svg' : 'ic_bottom_star_normal.svg';
}
...
// 点击插入图片
this.clickAddPicture = () = > {
this.imageSrc = this.chooseImage();
if (this.imageSrc === '') {
prompt.showToast({
message: 'Not anymore pictures'
});
} else {
this.imageArr = this.notesInfo.imageArr;
this.imageArr.push(this.imageSrc);
this.isDataChanged = true;
}
}
// ConfirmDialog.ets
if (this.type === CommonConstants.SAVE_DIALOG) {
this.confirm = async () = > {
let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME);
if (this.operationType === CommonConstants.ADD_NOTE) {
this.noteIdArray.push(new NoteIdBean(this.notesInfo.noteId));
preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(this.noteIdArray));
preferences.flush();
}
// 保存备忘录数据实时更新
let newNotes = this.notesInfo;
await preferences.put(this.notesInfo.noteId, JSON.stringify(newNotes));
await preferences.flush();
router.replaceUrl({
url: 'pages/NoteHomePage'
});
}
}
上述章节介绍了数据库的新增与更新,此章节来介绍删除操作。效果如图所示:
在BottomBar.ets中点击删除按钮,弹出自定义弹窗选择“是否删除”。在ConfirmDialog.ets中添加删除逻辑,删除操作会调用preferences实例的delete方法,将对应noteId的备忘录数据从数据库中删除,最后执行实例的flush方法实现持久化。
// BottomBar.ets
export default struct BottomBar {
...
deleteDialogController: CustomDialogController = new CustomDialogController({
builder: ConfirmDialog({
notesInfo: $notesInfo,
operationType: $operationType,
noteIdArray: $noteIdArray,
type: CommonConstants.DELETE_DIALOG
}),
autoCancel: true,
alignment: DialogAlignment.Bottom,
offset: { dx: $r('app.float.dialog_offset_x'), dy: $r('app.float.dialog_margin_bottom') }
});
...
build() {
...
Column() {
Image($r('app.media.ic_bottom_delete'))
.width($r('app.float.ic_bottom_picture_size'))
.aspectRatio(1)
Text($r('app.string.delete_note'))
.fontSize($r('app.float.font_size_smallest'))
.margin({ top: $r('app.float.bottom_txt_margin') })
}
.onClick(() = > {
this.clickDelete = () = > {
if (this.operationType === CommonConstants.MODIFY_NOTE) {
this.deleteDialogController.open();
} else {
prompt.showToast({
message: 'The addition operation cannot be deleted'
});
}
}
this.clickDelete();
})
...
}
...
}
// ConfirmDialog.ets
if (this.type === CommonConstants.SAVE_DIALOG) {
...
} else {
// 删除备忘录数据
this.confirm = async () = > {
let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME);
await preferences.delete(this.notesInfo.noteId);
await preferences.flush();
router.replaceUrl({
url: 'pages/NoteHomePage'
});
}
}
this.confirm();
})
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !