当前位置: 首页 > news >正文

HarmonyOS NEXT 诗词元服务项目开发上架全流程实战(一、项目介绍及实现效果)

在当今数字化时代,如何让传统文化与现代科技相结合,成为了一个值得思考的问题。诗词作为中国传统文化的重要组成部分,承载着丰富的历史信息和文化内涵。为了让更多人了解和欣赏诗词的魅力,我们决定开发一款基于HarmonyOS NEXT的诗词元服务应用。这款应用不仅能够提供诗词的欣赏功能,还能通过现代化的交互方式,让传统诗词焕发出新的生命力。

项目目标

目标是打造一个精神的栖息地,为文人墨客和诗词爱好者提供一个互动交流的平台。同时,我们希望通过这个项目,让更多人能快速上述鸿蒙应用开发,不要说你不会,更不要说难。直接从实战上手,直接看到学习成果,获得成就感。完整展示从开发到打包,从签名上架的全套流程。同时能够欣赏到中国传统文化的精髓,体验诗词带来的美好感受。在开发过程中,我们将注重用户体验,确保用户能够便捷地翻阅诗词,以及获取诗词的详细信息。

在这里插入图片描述

功能特性

  1. 诗词展示:展示诗词的标题、作者、内容,支持翻页操作和查看诗词注释。
  2. 对话框交互:包含诗词解说对话框和建议与反馈对话框,提升用户交互体验。
  3. 页面导航:可通过 AtomicServiceTabs 组件在首页和关于页面间切换。
  4. 个人中心:展示作者及个人信息。

诗词展示

诗词展示功能是应用的核心之一,将展示诗词的标题、作者和正文内容。用户可以通过翻页操作来浏览不同的诗词。此外,我们还为每首诗词提供了详细的注释,包括词句的解释、背景介绍和作者的注解,帮助用户更好地理解诗词。

对话框交互

我们加入了诗词解说对话框和建议与反馈对话框,以提升用户的交互体验。诗词解说对话框可以显示诗词的详细解释、背景和注解,而建议与反馈对话框则让用户可以向我们提出建议或反馈意见,帮助我们不断改进应用。
在这里插入图片描述

页面导航

我们使用了AtomicServiceTabs组件,通过底部导航栏实现了首页和关于页面的切换。首页主要展示诗词内容,而关于页面则介绍项目背景和开发团队的信息。

数据内容

诗词数据以本地JSON格式存储,示例如下:

{"poet": "伟人","title": "致彭德怀同志","content": "山高路远坑深,大军纵横驰奔。\r\n谁敢横刀立马?唯我彭大将军。","intro": "1935年10月21日,红军到达吴起镇,毛泽东亲自督战迎敌,部署好战斗后,把指挥事宜交给彭德怀处理,战斗结束后,他当场赋此诗赠予彭德怀。这首诗中字里行间跳动着凯歌的欢快音符,更跳动着革命者那颗“爱将”之心。","comment": "","trans": "吴起镇山险路长沟深,中央红军骑马奔驰杀敌。有谁敢横刀立马,只有我彭德怀大将军。","annot": "坑深:地势险峻。\r\n唯我彭大将军:毛泽东写诗赠于,首句即用电文句,但改“沟深”为“坑深”。彭德怀收到这首诗后,将诗的末句“唯我彭大将军”改为“唯我英勇红军”,然后将原诗还给毛泽东。"
}

实现概述

读取JSON文件

为了实现诗词数据的展示,我们首先需要读取本地的JSON文件。以下是读取JSON文件的代码实现:

import { common } from "@kit.AbilityKit";
import { util } from "@kit.ArkTS";/*** @author: * @date: 2024/12/7 13:59* @description: 读取JSON文件* @version:*/
export function ReadJsonFile(fileStr: string): Promise<Array<Record<string, Object>>>{return new Promise<Array<Record<string, Object>>>(async (success, error) => {try {let context: common.UIAbilityContext = getContext() as common.UIAbilityContext;let jsonFile = await context.resourceManager.getRawFileContent(fileStr);let jsonString: string = util.TextDecoder.create('utf-8', {ignoreBOM: true}).decodeToString(jsonFile, { stream: false});success(JSON.parse(jsonString))} catch (e) {error([])}})
}

首页实现

首页通过AtomicServiceTabs组件实现页签切换,并展示诗词内容。以下是首页的实现代码:

import { AboutView } from '../view/AboutView';
import { HomeView } from '../view/HomeView';
import { AtomicServiceTabs, TabBarOptions, TabBarPosition } from '@ohos.atomicservice.AtomicServiceTabs';
import { CustomConstants } from '../common/constants/CustomConstants';
import { AtomicServiceNavigation } from '@ohos.atomicservice.AtomicServiceNavigation';
import { ViewData } from '../common/entity/ViewData';
import PersistentStorage from '@ohos.data.PersistentStorage';PersistentStorage.persistProp<ViewData[]>(CustomConstants.PRELOAD_DATA_KEY, []);
PersistentStorage.persistProp<string>(CustomConstants.PRELOAD_STATUS_KEY, "succeed");@Entry
@Component
struct Index {@State currentIndex: number = 0;@State title: ResourceStr = $r('app.string.app_name');childNavStack: NavPathStack = new NavPathStack();@BuildertabHomeContent() {HomeView()}@BuildertabAboutContent() {AboutView()}@BuildernavigationContent() {AtomicServiceTabs({tabContents: [() => {this.tabHomeContent()},() => {this.tabAboutContent()}],tabBarOptionsArray: [new TabBarOptions($r('app.media.house'), '', $r('app.color.grayscale_color'), $r('app.color.title_font_color')),new TabBarOptions($r('app.media.person'), '', $r('app.color.grayscale_color'), $r('app.color.title_font_color'))],tabBarPosition: TabBarPosition.BOTTOM,barBackgroundColor: $r('app.color.primary_color'),barOverlap: true,onTabBarClick: (index: number) => {if (index === 0) {this.title = $r('app.string.app_name');} else {this.title = "关于我们";}}})}@BuilderpageMap(name: string) {}build() {Column() {AtomicServiceNavigation({navigationContent: () => {this.navigationContent();},title: this.title,titleOptions: {backgroundColor: $r('app.color.primary_color'),isBlurEnabled: true},navDestinationBuilder: this.pageMap,navPathStack: this.childNavStack,mode: NavigationMode.Stack})}.width(CustomConstants.PAGE_FULL).height(CustomConstants.PAGE_FULL)}
}

诗词展示实现

HomeView中,我们实现了诗词的展示和翻页功能。以下是诗词展示的实现代码:

import { curves } from "@kit.ArkUI";
import { CustomConstants } from "../common/constants/CustomConstants";
import { IntroDialogView } from "../common/dialog/IntroDialogView";
import { ReadJsonFile } from "../common/utils/ReadJsonFile";
import AlertDialog from '@ohos.promptDialog.AlertDialog';
import { DialogAlignment, BlurStyle } from '@ohos.promptDialog';@Preview
@Component
export struct HomeView {@State viewData: Array<Record<string, any>> = [];@State currentIndex: number = 0;re: RegExp = new RegExp("[。!?]");async aboutToAppear(): Promise<void> {await ReadJsonFile("data.json5").then((data) => {this.viewData = data as Array<Record<string, any>>;});}build() {Column() {Stack() {Scroll() {Flex({ direction: FlexDirection.Row, wrap: FlexWrap.NoWrap }) {Column({ space: CustomConstants.ROW_COLUMN_SPACES[3] }) {Text(this.viewData[this.currentIndex]?.title ?? "").width($r('app.float.size_20')).fontSize($r('app.float.font_size_18')).fontWeight(FontWeight.Bolder).fontColor($r('app.color.title_font_color'))Text(this.viewData[this.currentIndex]?.poet ?? "").width($r('app.float.size_20')).fontSize($r('app.float.font_size_14')).fontWeight(FontWeight.Normal).textAlign(TextAlign.Center).fontColor($r('app.color.start_window_background')).backgroundColor($r('app.color.tag_color')).backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THIN).borderRadius($r('app.float.size_16')).padding({top: $r('app.float.size_16'),bottom: $r('app.float.size_16')})}.justifyContent(FlexAlign.Center).padding({left: $r('app.float.size_8'),right: $r('app.float.size_8')})Scroll() {Scroll() {Row({ space: 10 }) {ForEach(this.viewData[this.currentIndex]?.content.split(this.re), (item: string) => {if (item.trim() != "") {Column({ space: CustomConstants.ROW_COLUMN_SPACES[3] }) {Text(item.trim().replace("\n", "").replace("\r", "") + "。").width($r('app.float.size_20')).fontSize($r('app.float.font_size_18')).fontColor($r('app.color.title_font_color')).fontWeight(FontWeight.Medium)}.justifyContent(FlexAlign.Start).padding({left: $r('app.float.size_8'),right: $r('app.float.size_8')})}})}.justifyContent(FlexAlign.Start).alignItems(VerticalAlign.Top).padding({left: $r('app.float.size_8'),right: $r('app.float.size_8')}).transition(this.effect)}.layoutWeight(1).scrollBar(BarState.Off).scrollable(ScrollDirection.Horizontal).edgeEffect(EdgeEffect.Spring)}.layoutWeight(1).scrollBar(BarState.Off).scrollable(ScrollDirection.Vertical).edgeEffect(EdgeEffect.Spring)}.padding($r('app.float.size_20'))}.scrollable(ScrollDirection.Horizontal).scrollBar(BarState.Off).width(CustomConstants.PAGE_FULL).height(CustomConstants.PAGE_FULL).borderRadius($r('app.float.size_16')).shadow({radius: $r('app.float.size_10'),color: $r('app.color.primary_color')})Row() {Button() {// 上一页Text() {SymbolSpan($r('sys.symbol.chevron_left')).fontSize($r('app.float.font_size_24')).fontColor([$r('app.color.start_window_background')])}.width($r('app.float.size_81')).height($r('app.float.size_32')).textAlign(TextAlign.Center)}.type(ButtonType.Capsule).backgroundColor($r('app.color.secondary_color')).onClick(() => {this.currentIndex--;if (this.currentIndex < 0) {this.currentIndex = 0;}})// 注释Button() {Text() {SymbolSpan($r('sys.symbol.keyboard_badge_zhuyin')).fontSize($r('app.float.font_size_24')).fontColor([$r('app.color.start_window_background')])}.width($r('app.float.size_48')).height($r('app.float.size_48')).textAlign(TextAlign.Center)}.type(ButtonType.Circle).backgroundColor($r('app.color.primary_color')).onClick(() => {AlertDialog.show({title: this.viewData[this.currentIndex].title + '【释义】',message: '解释:\n' + this.viewData[this.currentIndex].trans + '\n\n赏析:\n' + this.viewData[this.currentIndex].intro + '\n\n注解:\n' + this.viewData[this.currentIndex].annot + '\n\n评价:\n' + this.viewData[this.currentIndex].comment,autoCancel: true,alignment: DialogAlignment.Center,backgroundColor: $r('app.color.primary_color'),backgroundBlurStyle: BlurStyle.NONE})})// 下一页Button() {Text() {SymbolSpan($r('sys.symbol.chevron_right')).fontSize($r('app.float.font_size_24')).fontColor([$r('app.color.start_window_background')])}.width($r('app.float.size_81')).height($r('app.float.size_32')).textAlign(TextAlign.Center)}.type(ButtonType.Capsule).backgroundColor($r('app.color.secondary_color')).onClick(() => {this.currentIndex++;if (this.currentIndex >= this.viewData.length) {this.currentIndex = 0;}})}.width(CustomConstants.PAGE_FULL).height($r('app.float.size_48')).justifyContent(FlexAlign.SpaceEvenly)}.width(CustomConstants.PAGE_FULL).height(CustomConstants.PAGE_FULL).alignContent(Alignment.Bottom)}.width(CustomConstants.PAGE_FULL).height(CustomConstants.PAGE_FULL).backgroundColor($r('app.color.mask_color')).padding({top: $r('app.float.size_12'),right: $r('app.float.size_16'),bottom: $r('app.float.size_64'),left: $r('app.float.size_16')})}// 创建TransitionEffectprivate effect: TransitionEffect =// 创建默认透明度转场效果,并指指定springMotion(0.6, 0.8)曲线TransitionEffect.OPACITY.animation({ curve: curves.springMotion(0.6, 0.8) })// 通过combine方法,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion(0.6, 0.8).combine(TransitionEffect.scale({ x: 0, y: 0 }))// 添加旋转转场效果,这里的动画参数会跟随上面带animation的TransitionEffect,也就是springMotion().combine(TransitionEffect.rotate({ angle: 90 }))// 添加平移转场效果,这里的动画参数使用指定的springMotion().combine(TransitionEffect.translate({ y: 150 }).animation({ curve: curves.springMotion() }))// 添加move转场效果,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion().combine(TransitionEffect.move(TransitionEdge.END));
}

总结

通过上述代码,我们实现了从读取JSON文件到展示诗词内容的全流程。接下来的开发中,我们将进一步优化用户体验,增强应用功能,确保用户能够流畅地欣赏到中国传统文化的瑰宝。

作者介绍

作者:csdn猫哥

原文链接:https://blog.csdn.net/yyz_1987

团队介绍

坚果派团队由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉等相关内容,团队成员聚集在北京、上海、南京、深圳、广州、宁夏等地,目前已开发鸿蒙原生应用和三方库60+,欢迎交流。


http://www.mrgr.cn/news/100642.html

相关文章:

  • CogCoM: A Visual Language Model with Chain-of-Manipulations Reasoning 学习笔记
  • 【金仓数据库征文】加速数字化转型:金仓数据库在金融与能源领域强势崛起
  • 51c大模型~合集122
  • 2025年五一数学建模竞赛AI辅助全网专业性第一
  • 在线图书管理系统的结构化需求分析过程讲解
  • Spark知识总结
  • 隐形革命:环境智能如何重构“人-机-境“共生新秩序
  • lmms-eval--微调实战笔记
  • 52.[前端开发-JS实战框架应用]Day03-AJAX-插件开发-备课项目实战-Lodash
  • 相机-IMU联合标定:相机标定
  • 如何让自己的博客可以在百度、谷歌、360上搜索到(让自己写的CSDN博客可以有更多的人看到)
  • vue3代码规范管理;基于vite和vue3、 eslint、prettier、stylelint、husky规范;git触发eslint校验
  • 【Castle-X机器人】模块安装与调试
  • FFTW3.3.10库与QT结合的使用
  • Ant(Ubuntu 18.04.6 LTS)安装笔记
  • IP查询专业版:支持IPv4/IPv6自动识别并切换解析的API接口使用指南
  • Ubuntu安装SRS流媒体服务
  • 打印及判断回文数组、打印N阶数组、蛇形矩阵
  • Vue组件开发进阶:从通信原理到DOM异步更新实战
  • 【MySQL】Java代码操作MySQL数据库 —— JDBC编程