HarmonyOS鸿蒙Next“说书人”项目单机版实践案例

HarmonyOS鸿蒙Next“说书人”项目单机版实践案例 前段时间开发了一个软件,取名为“说书人”,后由于备案暂时没有通过,于是删除了联网功能,重新做了一个单机版,这里对于单机版的开发实践案例进行一个发出,希望能帮助到大家。

文章最后给出了AtomGit仓库地址

pages/Data 目录

此目录下存储了项目中会使用到的数据

AppData.ets

此处存储了应用的版本号信息

export interface appAloneDataTem {
  appName: string,
  appVersion: string,
  appLogin: boolean
}

export let appAloneData: appAloneDataTem = {
  appName: '说书人',
  appVersion: 'V 1.0.0',
  appLogin: false
}

PersistentStorage.persistProp('appData', appAloneData)

bookData.ets

此处存储了书本信息

export interface bookDataTemplate{
  bookID: number,
  bookName: string,
  bookBrief: string,
  // bookHead: string,
  bookLabel: string[],

  // 发布状态:真为公有,假为私有
  releaseState: boolean,

  createUserID: number,
  createUserName: string,

  createUserOpen: boolean,

  haveRoleID: string[],
  chapterIndex: string
}

export let bookData: bookDataTemplate = {
  bookID: 0,
  bookName: '',
  bookBrief: '简介',
  // bookHead: "",
  bookLabel: [],

  releaseState: false,

  createUserID: 0,
  createUserName: '未知用户',

  createUserOpen: true,
  haveRoleID: [],
  chapterIndex: "0",
}

export let bookDataList: bookDataTemplate[] = [
  {
    bookID: 0,
    bookName: '开幕',
    bookBrief: '《说书人》的第一幕',
    // bookHead: "",
    bookLabel: [],

    releaseState: false,

    createUserID: 0,
    createUserName: '未知用户',

    createUserOpen: true,
    haveRoleID: [],
    chapterIndex: "0",
  }
]

PersistentStorage.persistProp('bookData', bookData)
PersistentStorage.persistProp('bookDataList', bookDataList)

frameData.ets

此处存储了项目所需要使用到的一些设置信息,以及公有的组件

import router from '[@ohos](/user/ohos).router';

// 画面设置
export interface frame{
  typefaceSize: number,
  backGround: ResourceColor,
}

export let frameDataSet: frame = {
  typefaceSize: 16,
  backGround: "#ffffff",
}

// 颜色加法
export let ThisPagefontColor: ResourceColor =
  '#' +
  setTenSix(frameDataSet.backGround.toString().slice(1,3)) +
  setTenSix(frameDataSet.backGround.toString().slice(3,5)) +
  setTenSix(frameDataSet.backGround.toString().slice(5,7))

// 十进制转十六进制
function setTenSix(Color: string){
  let colorData = (255 - parseInt('0x' + Color.toString()))
  return colorData <= 15 ? '0' + colorData.toString(16) : colorData.toString(16)
}

PersistentStorage.persistProp('frame', frameDataSet)

PersistentStorage.persistProp('fontColor', ThisPagefontColor)

[@Component](/user/Component)
export struct frameData {
  [@StorageProp](/user/StorageProp)('frame')  frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor

  build(){
    Text('Back')
      .fontColor(this.ThisColor)
      .fontSize(this.frameData.typefaceSize + 6)
      .onClick(() => {
        router.back()
      })
  }
}

readBookCharpter.ets

此处存储了章节信息

// 章节信息
export interface readBookCharpterTemplate{
  // 章节ID
  articleID: number,
  // 章节索引
  chapterIndex: string,
  // 章节内容
  dialogueList: string,
  // 造物者之ID
  createUserID: string,
  // 归属之书
  ascriptionBookID: number,
}

export let readBookCharpterData: readBookCharpterTemplate = {
  articleID: 0,
  chapterIndex: "1-1",
  dialogueList: "",
  createUserID: "",
  ascriptionBookID: 0
}

export let readBookCharpterDataList: readBookCharpterTemplate[] = [
  {
    articleID: 0,
    chapterIndex: "1-1",
    dialogueList: "left|官方001|大家好!,left|官方001|欢迎使用《说书人》APP,它是一款面向角色编写剧本的软件 ,left|官方001|你可以在这款软件中定义角色,为多个角色之间编写剧本,还可以编写角色的关系网,查看角色的时间线等等... ,left|官方001|虽然在“还可以”之后的功能都还没实现就是了 ,left|官方001|截止编写本幕为止,软件只完成了基本功能,还有相当多不完善的地方,都会在为了慢慢解决的 ,left|官方001|十分感谢您对《说书人》的使用,如果使用过程中存在什么意见或建议,可以添加客服QQ提出 ,left|官方001|客服QQ: 1827650871",
    createUserID: "",
    ascriptionBookID: 0
  }
]

PersistentStorage.persistProp('readBookCharpterData', readBookCharpterData)
PersistentStorage.persistProp('readBookCharpterDataList', readBookCharpterDataList)

roleData.ets

此处存储了角色会使用的数据

export interface roleCustom{
  name: string,
  value: string
}

export interface roleDataTemplate{
  roleID: number,
  roleName: string,
  roleAge: string,
  roleGender: string,
  roleBrief: string,
  roleHead: string,
  roleLabel: string[],
  roleCustom: roleCustom[],

  // 发布状态:真为公有,假为私有
  releaseState: boolean,

  // 创造他的用户
  createUserID: number,
  createUserName: string,

  // 用户是否公开
  createUserOpen: boolean,

  // 有关系的角色和出现过的书籍
  relevantRoleID: string[],
  relevantBookID: string[]
}

export let roleData: roleDataTemplate = {
  roleID: 0,
  roleName: '',
  roleAge: '0',
  roleGender: '',
  roleBrief: '简介',
  roleHead: "",
  roleLabel: [],
  roleCustom: [],

  releaseState: false,

  createUserID: 0,
  createUserName: "未知用户",

  createUserOpen: true,
  relevantRoleID: [],
  relevantBookID: []
}

export let roleDataList: roleDataTemplate[] = [
  {
    roleID: 0,
    roleName: '官方001',
    roleAge: '18',
    roleGender: '男',
    roleBrief: '一个勤劳的打工人',
    roleHead: "",
    roleLabel: [],
    roleCustom: [],

    releaseState: false,

    createUserID: 0,
    createUserName: "未知用户",

    createUserOpen: true,
    relevantRoleID: [],
    relevantBookID: []
  },
]

PersistentStorage.persistProp('roleData', roleData)
PersistentStorage.persistProp('roleDataList', roleDataList)

inspirationTem.ets

此处存储了灵感信息

export interface inspirationTem {
  inspirationID: number,
  inspirationTitle: string,
  inspirationMain: string
}

export let inspirationData: inspirationTem = {
  inspirationID: 0,
  inspirationTitle: '标题',
  inspirationMain: '正文'
}

export let inspirationDataList: inspirationTem[] = [
  {
    inspirationID: 0,
    inspirationTitle: '标题',
    inspirationMain: '正文'
  }
]

PersistentStorage.persistProp('inspirationData', inspirationData)
PersistentStorage.persistProp('inspirationDataList', inspirationDataList)

以上,便是整个应用所使用的数据信息,使用持久化存储将数据存储在本地

接下来,便是主要页面

pages/index.ets

import router from '[@ohos](/user/ohos).router'
import { frame, frameDataSet, ThisPagefontColor } from './Data/frameData'
import { userOwnData, userOwn } from './Data/userData'

import promptAction from '[@ohos](/user/ohos).promptAction';

[@Component](/user/Component)
struct Index {

  [@StorageProp](/user/StorageProp)('frame') frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor

  @StorageLink('userOwnData') userOwn: userOwnData = userOwn

  [@State](/user/State) indexTime: number = 0

  onPageShow(): void {
    promptAction.showToast({
      message: "欢迎使用说书人"
    })
    this.indexTime = setTimeout(() => {
    router.clear()
      router.replaceUrl({
        "url": "pages/Main/userSpace",
        "params": {
          "goPageIndex" : 0
        }
      })
      promptAction.showToast({
        message: '登陆成功!'
      })
    }, 3000)
  }

  build(){
    Flex({
      justifyContent: FlexAlign.Center
    }){
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r('app.media.fengmian'))
    .backgroundImageSize(ImageSize.Cover)
    .backgroundColor(this.frameData.backGround)
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
    .onClick(() => {
      clearTimeout(this.indexTime)
      router.clear()
      router.replaceUrl({
        "url":"pages/Main/userSpace",
        "params":{
          "goPageIndex" : 0
        }
      })
      promptAction.showToast({
        message: '登陆成功!'
      })
    })
  }
}

pages/loginPOP.ets

import { frame, frameDataSet, ThisPagefontColor, frameData } from './Data/frameData'
import router from '[@ohos](/user/ohos).router';

@CustomDialog
export default struct agreePage {

  agreePage: CustomDialogController

  onCancel: () => void = () => {}
  onJUJUE: () => void = () => {}


  [@StorageProp](/user/StorageProp)('frame') frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor


  build(){
    /* 用户名和需要修改的参数都由外部传递
      此处只涉及数据修改任务*/
    Flex(){
      Column({space: 16}){
        Row(){
          Text('《用户协议》与《隐私政策》提示')
            .fontSize(this.frameData.typefaceSize + 4)
            .fontColor(ThisColor)
        }.width('100%')
        .justifyContent(FlexAlign.Center)
        .padding({
          top: 24,
          left: 24
        })

        Scroll(){
          Column({ space: 12 }){
              Text(`
您需要阅读并同意隐私政策和用户协议后,才能使用《说书人》软件。

如果您不同意,很遗憾我们无法为您提供相关服务。
              `)
                .fontColor(ThisColor)
                .fontSize(frameData.typefaceSize + 2)
            Flex({
              wrap: FlexWrap.Wrap
            }){
              Text('您可以点击阅读')
                  .fontColor(ThisColor)
                  .fontSize(frameData.typefaceSize + 2)
              Text(`《用户协议》`)
                .fontColor('#4a90e2')
                .fontSize(frameData.typefaceSize + 2)
                .onClick(() => {
                  router.pushUrl({
                    url: "pages/agreement/userAgreememt"
                  })
                  this.agreePage.close()
                })
              Text(`与`)
                .fontColor(ThisColor)
                .fontSize(frameData.typefaceSize + 2)
              Text(`《隐私政策》`)
                .fontColor('#4a90e2')
                .fontSize(frameData.typefaceSize + 2)
                .onClick(() => {
                  router.pushUrl({
                    url: "pages/agreement/privacyAgreement"
                  })
                  this.agreePage.close()
                })
              Text(`了解相关信息。
              `)
                .fontColor(ThisColor)
                .fontSize(frameData.typefaceSize + 2)
              Text(`如您同意,请点击“同意”开始接受我们的服务。`)
                .fontColor(ThisColor)
                .fontSize(frameData.typefaceSize + 2)
            }.width('100%')
          }
          .padding({
            left: 24,
            right: 24
          })
        }.edgeEffect(EdgeEffect.Spring)


        Row(){
          Button('同意 ')
            .type(ButtonType.Normal)
            .backgroundColor(frameData.backGround)
            .fontSize(frameData.typefaceSize + 2)
            .fontColor(ThisColor)
            .border({
              width: {
                left: 1,
                right: 1,
                bottom: 1
              },
              color: '#f4f6f5'
            })
            .width('50%')
            .onClick(() => {
              this.onCancel()
              this.agreePage.close()
            })

          Button('拒绝')
            .type(ButtonType.Normal)
            .backgroundColor(frameData.backGround)
            .fontSize(frameData.typefaceSize + 2)
            .fontColor(ThisColor)
            .border({
              width: {
                left: 1,
                right: 1,
                bottom: 1
              },
              color: '#f4f6f5'
            })
            .width('50%')
            .onClick(() => {
              this.onJUJUE()
              this.agreePage.close()
            })

        }
      }
    }.backgroundColor(frameData.backGround)

  }
}

pages/Main

以下是Main目录中的文件,此处存储了主要界面

userSpace.ets

import { frame, frameDataSet, ThisPagefontColor } from '../Data/frameData'

import scriptInterface from './mainPage/scriptPage'
import RelationshipPage from './mainPage/relationshipPage'

[@Component](/user/Component)
struct UserSpace {

  [@StorageProp](/user/StorageProp)('frame') frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor

  build(){
    Flex(){
      Tabs(){
        TabContent(){
          scriptInterface()
        }.tabBar('首页')
        TabContent(){
          RelationshipPage()
        }.tabBar('灵感')
      }.barPosition(BarPosition.End)
    }
    .backgroundColor(frameData.backGround)
  }
}

pages/Main/mainPage/scriptPage.ets

import { frame, frameDataSet, ThisPagefontColor } from '../../Data/frameData'
import { router } from '@kit.ArkUI'
import { roleDataList, roleDataTemplate, } from '../../Data/roleData'

import { standardCudeImage } from '../../template/textImgTemplate'
import { bookDataList, bookDataTemplate } from '../../Data/bookData'
import { it } from '[@ohos](/user/ohos)/hypium'

[@Component](/user/Component)
export default struct scriptInterface {

  [@StorageProp](/user/StorageProp)('frame') frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor

  [@StorageProp](/user/StorageProp)('roleDataList') roleDataList: roleDataTemplate[]  = roleDataList
  [@StorageProp](/user/StorageProp)('bookDataList') bookDataList: bookDataTemplate[] = bookDataList

  [@State](/user/State) openSet: boolean = false
  [@State](/user/State) ThisText: string = ''

  [@State](/user/State) sw:number = 0
  [@State](/user/State) sh:number = 0

  build(){
    Flex(){
      Stack({
        alignContent: Alignment.Top
      }){
        Column(){
          Row(){
            TextInput({placeholder: "搜索"})
              .width('90%')
              .textAlign(TextAlign.Center)
              .onChange(value => {
                ThisText = value
              })
            Text('+')
              .fontSize(32)
              .width(50)
              .textAlign(TextAlign.Center)
          }
          .width('100%')
          .justifyContent(FlexAlign.SpaceBetween)
          .onClick(() => {
            openSet = !openSet
          })
          Tabs(){
            // 角色
            TabContent(){
              Scroll(){
                Column({ space: 16 }){
                  ForEach(this.roleDataList, (item: roleDataTemplate, index) => {
                    if (item.roleName.includes(ThisText) || item.roleID.toString().includes(ThisText)) {
                      // 角色模板
                      Row({space: 16}){
                        Text(`${item.roleName}`)
                          .fontSize(16)
                          .width(90)
                          .height(120)
                          .borderRadius(16)
                          .backgroundColor(frameData.backGround)
                          .border({
                            width: 1
                          })
                          .borderRadius(16)
                          .textOverflow({overflow: TextOverflow.Ellipsis})
                          .padding(16)
                          .textAlign(TextAlign.Center)
                        Column({ space: 6 }){
                          Row(){
                            Text(`${item.roleName}`)
                              .fontSize(frameData.typefaceSize + 4)
                              .fontColor(ThisColor)
                              .fontWeight(600)
                          }
                          Row(){
                            Text(`${item.roleBrief}`)
                              .fontSize(frameData.typefaceSize - 2)
                              .fontColor(ThisColor)
                              .maxLines(2)
                              .textOverflow({overflow: TextOverflow.Ellipsis})
                          }.width('70%')
                          Row(){
                            ForEach(item.roleLabel, (item: string) => {
                              Text(`/ ${item} /`)
                                .fontSize(frameData.typefaceSize - 4)
                                .fontColor(ThisColor)
                                .fontWeight(200)
                            })
                          }
                        }.width('100%')
                        .alignItems(HorizontalAlign.Start)
                      }
                      .onClick(() => {
                        router.pushUrl({
                          "url": "pages/userSystem/userDetailed",
                          "params": {
                            "roleID": item.roleID
                          }
                        })
                      })
                    }
                  })
                }
              }
              .height('100%')
              .align(Alignment.Top)
              .edgeEffect(EdgeEffect.Spring)
              .padding({
                top: 12,
                bottom: 64
              })
            }.tabBar('角色')
            // 剧本
            TabContent(){
              Scroll(){
                // 剧本列表
                Column({ space: 16 }){
                  ForEach(this.bookDataList, (item: bookDataTemplate, index) => {
                    if (item.bookName.includes(ThisText) || item.bookID.toString().includes(ThisText)) {
                      // 剧本模板
                      Row({space: 16}){
                        Column({ space: 6 }){
                          Row(){
                            Text(item.bookName)
                              .fontSize(frameData.typefaceSize + 4)
                              .fontColor(ThisColor)
                              .fontWeight(600)
                          }.width('70%')
                          .justifyContent(FlexAlign.End)
                          Row(){
                            Text(item.bookBrief)
                              .fontSize(frameData.typefaceSize - 2)
                              .fontColor(ThisColor)
                              .maxLines(2)
                              .textOverflow({overflow: TextOverflow.Ellipsis})
                              .textAlign(TextAlign.End)
                          }.width('70%')
                          .justifyContent(FlexAlign.End)
                          Row(){
                            ForEach(item.bookLabel, (item: string) => {
                              Text(`/ ${item} /`)
                                .fontSize(frameData.typefaceSize - 4)
                                .fontColor(ThisColor)
                                .fontWeight(200)
                                .textAlign(TextAlign.End)
                            })
                          }.width('70%')
                          .justifyContent(FlexAlign.End)
                        }
                        .alignItems(HorizontalAlign.Start)
                        standardCudeImage(`${item.bookName}`, frameData.backGround, ThisColor)
                      }
                      .onClick(() => {
                        router.pushUrl({
                          url: "pages/scriptSystem/scriptDetailed",
                          params: {
                            "bookID": item.bookID,
                            "collection": false
                          }
                        })
                      })
                    }
                  })
                }
              }
              .height('100%')
              .align(Alignment.Top)
              .edgeEffect(EdgeEffect.Spring)
              .padding({
                top: 12,
                bottom: 64
              })
            }.tabBar('剧本')
          }.barPosition(BarPosition.Start)

        }
        .padding({
          left: 24,
          right: 24,
        })
        .align(Alignment.Top)
        .alignItems(HorizontalAlign.Start)

        // 阴影
        Column(){}
        .width('100%')
        .height('100%')
        .backgroundColor(Color.Black)
        .opacity(.6)
        .visibility(openSet ? Visibility.Visible : Visibility.None)
        .onClick(() => {
          openSet = false
        })

        // 角色剧本动态
        Column(){
          Row(){
            Text('角色')
              .fontSize(frameData.typefaceSize + 2)
              .fontColor(ThisColor)
          }.width(160)
          .justifyContent(FlexAlign.Center)
          .padding({
            left: 24,
            right: 24,
            top: 16,
            bottom: 16
          })
          .border({
            width: {
              bottom: 1
            }
          })
          .onClick(() => {
            router.pushUrl({
              "url": "pages/CreatePage/userCreate"
            })
            openSet = false
          })

          Row(){
            Text('剧本')
              .fontSize(frameData.typefaceSize + 2)
              .fontColor(ThisColor)
          }.width(160)
          .justifyContent(FlexAlign.Center)
          .padding({
            left: 24,
            right: 24,
            top: 16,
            bottom: 16
          })
          .border({
            width: {
              bottom: 1
            }
          })
          .onClick(() => {
            router.pushUrl({
              "url": "pages/CreatePage/scriptCreate"
            })
            openSet = false
          })
        }.border({ width: 1 })
        .borderRadius(2)
        .position({
          x: sw / 2 - 16,
          y: 36
        })
        .backgroundColor(Color.White)
        .visibility(openSet ? Visibility.Visible : Visibility.None)
      }
    }
    .backgroundColor(frameData.backGround)
    .onAreaChange((oldValue: Area, newValue: Area) => {
      sw = new Number(newValue.width).valueOf();
      sh = new Number(newValue.height).valueOf();
    });
  }
}

pages/Main/mainPage/relationshipPage

import { frame, frameDataSet, ThisPagefontColor } from '../../Data/frameData'
import { inspirationTem, inspirationData, inspirationDataList } from '../../Data/inspirationData'
import { promptAction } from '@kit.ArkUI'

[@Component](/user/Component)
export default struct RelationshipPage {

  [@StorageProp](/user/StorageProp)('frame') frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor

  @StorageLink('inspirationData') inspirationData: inspirationTem = inspirationData
  @StorageLink('inspirationDataList') inspirationDataList: inspirationTem[] = inspirationDataList

  [@State](/user/State) index: number = 0

  build(){
    Flex({
      justifyContent: FlexAlign.Center,
      wrap: FlexWrap.Wrap
    }){
        Column(){

          // 标题
          Row(){
            Text('灵感图谱')
              .fontSize(frameData.typefaceSize + 6)
              .fontColor(ThisColor)
              .letterSpacing(6)
          }
          .padding({
            top: 12, bottom: 12
          })
          .width('100%')
          .justifyContent(FlexAlign.Center)
          .border({
            width: {
              bottom: 2
            }
          })

          // 正文
          Column(){
            Row(){
              TextInput({ placeholder: "标题", text: inspirationDataList[index].inspirationTitle })
                .fontWeight(600)
                .fontSize(frameData.typefaceSize + 14)
                .placeholderFont({
                  size: frameData.typefaceSize + 14
                })
                .fontColor(ThisColor)
                .maxLength(16)
                .showUnderline(true)
                .onChange(value => {
                  inspirationDataList[index].inspirationTitle = value
                })
            }
            .padding(24)
            Scroll(){
              Column(){
                TextArea({placeholder: '在此输入内容', text: inspirationDataList[index].inspirationMain})
                  .backgroundColor(frameData.backGround)
                  .borderRadius(12)
                  .height('100%')
                  .maxLength(600)
                  .border({width: 1})
                  .fontSize(frameData.typefaceSize + 2)
                  .onChange(value => {
                    inspirationDataList[index].inspirationMain = value
                  })
              }.padding({
                left: 24, right: 24
              })
            }.edgeEffect(EdgeEffect.Spring)
            .height('70%')
            .width('100%')
            .align(Alignment.Top)
          }.width('100%')
          .alignItems(HorizontalAlign.Start)

          // 按钮
          Row(){
            Button('上一篇')
              .fontSize(frameData.typefaceSize + 6)
              .fontColor(ThisColor)
              .backgroundColor(frameData.backGround)
              .layoutWeight(1)
              .onClick(() => {
                if (index != 0) {
                  index -= 1
                } else {
                  promptAction.showToast({
                    message: "已到达第一篇"
                  })
                }
              })
            Button('下一篇')
              .fontSize(frameData.typefaceSize + 6)
              .fontColor(ThisColor)
              .backgroundColor(frameData.backGround)
              .layoutWeight(1)
              .onClick(() => {
                if (index == inspirationDataList.length - 1) {
                  if (inspirationDataList[index].inspirationTitle != '标题' ||
                  inspirationDataList[index].inspirationMain != '正文') {
                    inspirationDataList.push({
                      inspirationID: index,
                      inspirationTitle: '标题',
                      inspirationMain: '正文'
                    })
                    index ++
                  } else {
                    promptAction.showToast({
                      message: "已到达最后一篇"
                    })
                  }

                } else {
                  index ++
                }
              })
          }.height('10%')
          .width('100%')
          .justifyContent(FlexAlign.SpaceBetween)
      }
    }
  }
}

pages/userSystem/

以下是pages/userSystem/中的内容,存储了角色系统

userDetailed.ets

import { frame, frameDataSet, ThisPagefontColor, frameData } from '../Data/frameData'
import { roleDataTemplate, roleData, roleDataList } from '../Data/roleData'
import { promptAction, router } from '@kit.ArkUI'
import { standardCudeImage } from '../template/textImgTemplate'

[@Component](/user/Component)
struct UserDetailed {

  aboutToAppear(): void {
    let params = router.getParams() as Record<string, number>
    let roleID = params['roleID']

    for (let item of this.roleDataList) {
      if (item.roleID == roleID) {
        roleData = item
        break
      }
    }
  }

  [@StorageProp](/user/StorageProp)('frame') frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor
  [@StorageProp](/user/StorageProp)('roleDataList') roleDataList: roleDataTemplate[] = roleDataList

  [@State](/user/State) roleData: roleDataTemplate = roleData
  [@State](/user/State) openText: boolean = false

  build(){
    Flex({
      wrap: FlexWrap.Wrap
    }){
      Column({ space: 24 }){
        // 标题
        Row(){
          Row(){
            Text('Back')
              .fontColor(ThisColor)
              .fontSize(frameData.typefaceSize + 6)
              .onClick(() => {
                router.back()
              })
              .width(100)
          }

          Text(roleData.roleName)
            .fontSize(frameData.typefaceSize + 8)
            .fontColor(ThisColor)

          Text('')
            .width(100)
            .textAlign(TextAlign.End)

        }.width('100%')
        .justifyContent(FlexAlign.SpaceBetween)

        Scroll(){
          Column({ space: 24 }){
            Row({space: 16}){
              Text(roleData.roleName)
                .fontSize(24)
                .width(120)
                .height(120)
                .borderRadius(60)
                .backgroundColor(frameData.backGround)
                .border({
                  width: 1
                })
                .textOverflow({overflow: TextOverflow.Ellipsis})
                .padding(2)
                .textAlign(TextAlign.Center)
                .letterSpacing(3)
              Column({ space: 9 }){

                // 书名
                Row(){
                  Text(roleData.roleName)
                    .fontSize(frameData.typefaceSize + 6)
                    .fontColor(ThisColor)
                    .fontWeight(600)
                }

                // ID
                Row(){
                  Text(String(roleData.roleID))
                    .fontSize(frameData.typefaceSize - 4)
                    .fontColor(Color.Gray)
                    .fontWeight(400)
                }

                // 标签
                Row({ space: 6 }){
                  ForEach(roleData.roleLabel, (item: string) => {
                    Text(item)
                      .textCare(frameData.typefaceSize - 3)
                  })
                }
              }.width('100%')
              .alignItems(HorizontalAlign.Start)
              .height(120)
            }

            // 简介
            Column({ space: 12 }){
              Text('简介')
                .fontSize(frameData.typefaceSize + 4)
                .fontColor(ThisColor)
                .fontWeight(600)
              Row(){
                Text(roleData.roleBrief)
                  .maxLines(openText ? 999 : 4)
                  .textOverflow({overflow: openText ? TextOverflow.None : TextOverflow.Ellipsis })
                  .fontSize(frameData.typefaceSize)
                  .fontColor(ThisColor)
              }.width('100%')
              Row(){
                Text(openText ? '收起' : '展开')
                  .fontSize(frameData.typefaceSize - 2)
                  .fontColor(ThisColor)
                  .fontWeight(300)
                  .onClick(() => {
                    openText = !openText
                  })
              }.width('100%')
            }.width('100%')
            .alignItems(HorizontalAlign.Start)

          }
          .alignItems(HorizontalAlign.Start)
          .height('100%')
        }.edgeEffect(EdgeEffect.Spring)
        .height('87%')


        // 目录开始阅读收藏
        Row(){
          Text('')
            .width(50)

          Text('解锁详细档案')
            .fontSize(frameData.typefaceSize + 2)
            .fontColor(ThisColor)
            .onClick(() => {
              router.pushUrl({
                "url": "pages/userSystem/userPages/userArchives",
                "params": {
                  "roleID": roleData.roleID
                }
              })
            })

          Text('')
            .width(50)
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .alignItems(VerticalAlign.Center)
        .border({
          width: {
            top: 2
          }
        })
        .padding({
          top: 16
        })
      }
      .padding({
        top: 16,
        left: 24,
        right: 24,
        bottom: 16
      })
    }.height('100%')
  }
}

pages/userSystem/userPages

以下是pages/userSystem/userPages/中的内容,存储了角色详细档案

UserArchives.ets

import { frame, frameDataSet, ThisPagefontColor, frameData } from '../../Data/frameData'
import { roleDataTemplate, roleData, roleDataList, roleCustom } from '../../Data/roleData'
import { standardCudeImage } from '../../template/textImgTemplate'
import router from '[@ohos](/user/ohos).router';

[@Component](/user/Component)
struct UserArchives {

  aboutToAppear(): void {
    let params = router.getParams() as Record<string, number>
    let roleID = params['roleID']

    for (let item of this.roleDataList) {
      if (item.roleID == roleID) {
        roleData = item
        break
      }
    }
  }

  [@StorageProp](/user/StorageProp)('frame') frameData: frame = frameDataSet
  [@StorageProp](/user/StorageProp)('fontColor') ThisColor: ResourceColor = ThisPagefontColor
  [@StorageProp](/user/StorageProp)('roleDataList') roleDataList: roleDataTemplate[] = roleDataList

  [@State](/user/State) roleData: roleDataTemplate = roleData

  [@State](/user/State) sw: number = 0
  [@State](/user/State) sh: number = 0

  build(){
    Flex(){
      Scroll(){
        Column({ space: 12 }){
          // 标题
          Row(){
            frameData()
              .width(50)
            Text(roleData.roleName)
              .fontSize(frameData.typefaceSize + 8)
              .fontColor(ThisColor)
            Text('详细档案')
              .width(50)
              .fontSize(frameData.typefaceSize + 6)
              .fontColor(ThisColor)
          }.width('100%')
          .justifyContent(FlexAlign.SpaceBetween)
          .border({
            width: {
              bottom: 2
            }
          })
          .padding({
            top: 16,
            left: 24,
            right: 24,
            bottom: 16
          })

          Column({ space: 24 }){
            Stack(){
              Column({ space: 12 }){
                Row(){
                  Text('姓名:')
                    .fontSize(frameData.typefaceSize + 2)
                    .fontColor(ThisColor)
                  Text(roleData.roleName)
                    .fontSize(frameData.typefaceSize + 2)
                    .fontColor(ThisColor)
                }.width('100%')
                .justifyContent(FlexAlign.SpaceBetween)
                .margin({
                  top: 42
                })
                .padding({
                  left: 16,
                  right: 16,
                  top: 16,
                  bottom: 6
                })
                .border({
                  width: {
                    bottom: 1
                  }
                })

                Row(){
                  Text('性别:')
                    .fontSize(frameData.typefaceSize + 2)
                    .fontColor(ThisColor)
                  Text(roleData.roleGender)
                    .fontSize(frameData.typefaceSize + 2)
                    .fontColor(ThisColor)
                }.width('100%')
                .justifyContent(FlexAlign.SpaceBetween)
                .padding({
                  left: 16,
                  right: 16,
                  top: 16,
                  bottom: 6
                })
                .border({
                  width: {
                    bottom: 1
                  }
                })

                Row(){
                  Text('年龄:')
                    .fontSize(frameData.typefaceSize + 2)
                    .fontColor(ThisColor)
                  Text(roleData.roleAge)
                    .fontSize(frameData.typefaceSize + 2)
                    .fontColor(ThisColor)
                }.width('100%')
                .justifyContent(FlexAlign.SpaceBetween)
                .padding({
                  left: 16,
                  right: 16,
                  top: 16,
                  bottom: 6
                })
                .border({
                  width: {
                    bottom: 1
                  }
                })

                ForEach(roleData.roleCustom, (item: roleCustom, index) => {
                  Row(){
                    Text(`${item.name}: `)
                      .fontSize(frameData.typefaceSize + 2)
                      .fontColor(ThisColor)
                    Text(`${item.value}`)
                      .fontSize(frameData.typefaceSize + 2)
                      .fontColor(ThisColor)
                  }.width('100%')
                  .justifyContent(FlexAlign.SpaceBetween)
                  .padding({
                    left: 16,
                    right: 16,
                    top: 16,
                    bottom: 6
                  })
                  .border({
                    width: {
                      bottom: 1
                    }
                  })
                })

                Row(){
                  Text('简介:')
                    .fontSize(frameData.typefaceSize + 2)
                    .fontColor(ThisColor)
                  Text(`${roleData.roleBrief}`)
                    .fontSize(frameData.typefaceSize - 2)
                    .fontColor(ThisColor)
                    .width('70%')
                    .textAlign(TextAlign.End)
                }.width('100%')
                .justifyContent(FlexAlign.SpaceBetween)
                .padding({
                  left: 16,
                  right: 16,
                  top: 16,
                  bottom: 6
                })
                .border({
                  width: {
                    bottom: 1
                  }
                })
              }
              .border({width: 1})
              .borderRadius(16)
              .padding(16)

              Text(`${roleData.roleName}`)
                .fontSize(18)
                .width(90)
                .height(90)
                .borderRadius(45)
                .backgroundColor(frameData.backGround)
                .border({
                  width: 1
                })
                .textOverflow({overflow: TextOverflow.Ellipsis})
                .padding(2)
                .textAlign(TextAlign.Center)
                .letterSpacing(3)
                .position({
                  x: sw / 2 - 64,

更多关于HarmonyOS鸿蒙Next“说书人”项目单机版实践案例的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

HarmonyOS鸿蒙Next“说书人”项目单机版实践案例展示了如何在鸿蒙系统上开发一个单机版应用。该项目主要利用鸿蒙的分布式能力和ArkUI框架进行开发。项目核心功能包括语音识别、文本处理、语音合成等,通过鸿蒙的AI引擎和多媒体框架实现。

开发过程中,使用了鸿蒙的Ability框架进行页面管理,通过Page Ability和Service Ability实现应用的页面跳转和后台服务。语音识别功能通过调用鸿蒙的AI引擎接口实现,文本处理则利用鸿蒙的轻量级数据库进行数据存储和查询。语音合成功能通过鸿蒙的多媒体框架实现,支持多种语音输出格式。

项目还展示了如何利用鸿蒙的分布式数据管理功能,实现设备间的数据同步和共享。通过鸿蒙的分布式软总线技术,设备可以自动发现和连接,实现数据的无缝传输。

整体项目结构清晰,代码简洁,展示了鸿蒙系统在单机应用开发中的高效性和灵活性。通过该案例,开发者可以快速上手鸿蒙应用开发,并掌握其核心技术和框架。

更多关于HarmonyOS鸿蒙Next“说书人”项目单机版实践案例的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS鸿蒙Next的“说书人”项目单机版实践案例展示了如何利用鸿蒙系统的分布式能力,构建一个独立运行的故事讲述应用。通过鸿蒙的轻量级内核和高效资源管理,应用能够在单机环境下流畅运行,提供丰富的交互体验。开发者可以利用鸿蒙的UI框架和API,快速实现故事内容的加载、播放和用户交互功能,同时确保应用的稳定性和性能优化。

回到顶部