0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

HarmonyOS开发实例:【手机备忘录】

jf_46214456 来源:jf_46214456 作者:jf_46214456 2024-04-18 21:40 次阅读

介绍

本篇Codelab基于用户首选项,实现了备忘录新增、更新、删除以及查找等功能。效果如图所示:

相关概念

  • [用户首选项]:提供Key-Value键值型的数据处理能力,应用持久化轻量级数据,并对其修改和查询。
  • [Navigator]:路由容器组件,支持路由跳转以及子组件嵌入。

环境搭建

软件要求

  • [DevEco Studio]版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:[润和RK3568开发板]。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. [获取OpenHarmony系统版本]:标准系统解决方案(二进制)。以3.2 Release版本为例:
  2. 搭建烧录环境。
    1. [完成DevEco Device Tool的安装]
    2. [完成RK3568开发板的烧录]
    3. 鸿蒙开发指导文档:[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]
  3. 搭建开发环境。
    1. 开始前请参考[工具准备],完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导]创建工程(模板选择“Empty Ability”)。
    3. 工程创建完成后,选择使用[真机进行调测]。

搜狗高速浏览器截图20240326151450.png

代码结构解读

本篇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();
})

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 鸿蒙
    +关注

    关注

    55

    文章

    2097

    浏览量

    42270
  • HarmonyOS
    +关注

    关注

    79

    文章

    1940

    浏览量

    29532
  • OpenHarmony
    +关注

    关注

    24

    文章

    3485

    浏览量

    15410
收藏 人收藏

    评论

    相关推荐

    高颜值智能备忘录:不再遗忘任何要事

    摸出手机,在屏幕上找出备忘录,打字,纠错,排版...感觉好心塞...或者某天你在跑步,突然想起要给明天生日的女朋友买礼物,你在心里反复提醒,然后...跪了一晚上榴莲...面对这些情况,小编特别想给大家
    发表于 05-19 21:48

    PostgreSQL操作备忘录

    PostgreSQL 操作备忘录
    发表于 05-23 08:48

    【软通动力】HarmonyOS 手机通讯开发 实验指导手册 V 1.0

    人员开发技能前置要求,良好的 Java 基础和 sql 基础能力; 2. 配置好 HarmonyOS 移动应用开发环境 3. 完成鸿蒙手机通讯
    发表于 06-17 14:41

    UDS诊断命令备忘录

    UDS实践性强,逻辑复杂,很多服务非要体验过一次才能理解,导致包括我在内的初学者感觉晦涩难懂,不明觉厉,因此将自己的理解写下来、整理下来,与君共勉。零、UDS诊断命令备忘录一、简介UDS
    发表于 08-26 16:09

    怎样去搭建一种基于XR806的开源桌面备忘录

    本人计划怼一个开源桌面备忘录/天气预报/相册的项目基于XR806,同时学习鸿蒙操作系统获得晕哥赠送的开发板和芯片,目前处于环境搭建阶段看起来这个芯片玩的人比较少,目前遇到了问题,不知道如何解决,希望
    发表于 12-28 06:52

    keil5MDK和eplan2.7安装备忘录相关资料分享

    备忘录是防止以后安装的时候忘记步骤和主要问题。keil5安装我第一次使用的是软件安装管家的安装包,安完以后发现注册码一直弄不上,芯片库里边也没有STM32的芯片。然后找到大二时候电子工艺实习
    发表于 01-10 07:06

    戴姆勒与百度签署谅解备忘录

    7月25日,奔驰母公司戴姆勒与百度签署谅解备忘录,深化双方在自动驾驶和车联网等领域的战略合作。
    的头像 发表于 07-28 09:53 2591次阅读

    怎样将苹果备忘录笔记Notes“安装”到Win10上

    用iPhone、iPad的朋友一直有这样一个困惑,在手机平板上记录的苹果Notes备忘录笔记,要怎么在电脑上查看?
    的头像 发表于 03-31 16:22 6654次阅读

    慧荣科技与江波龙签署策略合作备忘录

    近日,慧荣科技与江波龙签署策略合作备忘录,旨在提升双方在手机存储市场的市场份额和综合产品竞争力,形成协同成长的深度合作伙伴关系。
    的头像 发表于 07-14 11:13 876次阅读

    设计模式:备忘录设计模式

    备忘录设计模式(Memento Design Pattern)是一种行为型设计模式,它的主要目的是在不破坏对象封装性的前提下,捕捉和保存一个对象的内部状态
    的头像 发表于 06-06 11:19 663次阅读

    设计模式行为型:备忘录模式

    备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。
    的头像 发表于 06-07 11:16 666次阅读
    设计模式行为型:<b class='flag-5'>备忘录</b>模式

    新思科技同越南政府签署谅解备忘录

    在越南总理范明政访美期间,新思科技与越南国家创新中心(nic)签署了关于培养越南集成电路设计人才的谅解备忘录,支持nic成立芯片设计孵化中心。另外,新思科技与越南信息通讯部下属的信息通信技术产业公司签订了支援越南半导体产业发展的谅解备忘录
    的头像 发表于 09-20 10:56 1319次阅读

    实践GoF的23种设计模式:备忘录模式

    相对于代理模式、工厂模式等设计模式,备忘录模式(Memento)在我们日常开发中出镜率并不高,除了应用场景的限制之外,另一个原因,可能是备忘录模式
    的头像 发表于 11-25 09:05 360次阅读
    实践GoF的23种设计模式:<b class='flag-5'>备忘录</b>模式

    江汽与华为签订合作备忘录 发力鸿蒙

    江汽与华为签订合作备忘录进一步深化双方合作;共同发力鸿蒙,江汽与华为将以OpenHarmony为底座的HarmonyOS启动鸿蒙原生应用开发;为用户提供更智能的体验。
    的头像 发表于 03-27 16:00 780次阅读

    容百科技宣布与SK On签订《合作备忘录

    本周,容百科技宣布与SK On签订《合作备忘录》,双方将围绕三元和磷酸锰铁锂正极开展深度合作。
    的头像 发表于 03-29 09:56 221次阅读