HarmonyOS APP应用开发项目- MCA助手(Day01持续更新中~)

news2024/12/23 13:57:59

简言:

gitee地址:https://gitee.com/whltaoin_admin/money-controller-app.git
端云一体化开发在线文档:
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/agc-harmonyos-clouddev-view-0000001700053733-V5

注:此App参照此教程进行二次修改:https://www.bilibili.com/video/BV1q5411v7o7

一、简介

moneyControllerApp(MCA)

这款精心打造的个人财务管理应用,是您理财路上的智慧伙伴。凭借前沿的智能化技术与直观易用的界面设计,它将化繁为简,让您的财务状况一目了然。无论是日常收支的记录,还是复杂财务的分析,都能轻松应对。它不仅帮助您有效掌控每一笔收入与支出,更助您洞悉财务趋势,科学规划未来,让财富增长之路更加清晰可见。从此,财务管理不再是难题,而是通往财务自由的桥梁。
在鸿蒙HarmonyOS Next版本的加持下,这款个人财务管理应用的性能与体验再度升级,成为您理财旅程中的超级智慧伙伴。鸿蒙系统的分布式技术,使得应用运行更加流畅稳定,数据同步更加快速准确,即使在多设备间切换,也能无缝衔接,确保您的财务信息实时更新,安全无忧。

二、什么是端云一体化开发

为丰富HarmonyOS对云端开发的支持、实现端云联动,DevEco Studio以Cloud Foundation Kit(云开发服务)为底座、在传统的“端开发”基础上新增“云开发”能力,开发者在创建工程时选择合适的云开发工程模板,即可在DevEco Studio内同时完成HarmonyOS应用的端侧与云侧开发,体验端云一体化协同开发。

三、开发环境介绍

编辑器DevEco Studio NEXT Developer Beta1
SDK11
操作系统Window 10 专业版
模拟器HarmonyOS Emulator Version: 5.0.3.405
HarmonyOS Version: HarmonyOS NEXT Developer Beta1

四、项目初始化

  • 步骤一:
/*
1 create project
2 application选择>>>[cloudDev] Empty Ability>>>Next
*/
  • 步骤二:输入图中信息后>>>点击Finish
    • 注意:存放路径不建议使用中文字符

image.png

  • 步骤三:进入项目主页>>>点击右上角的头像进行用户登录。

image.png

  • 步骤四:
// 1 进入网址并进行登录:https://developer.huawei.com/consumer/cn/
// 2 登录后在网站首页点击管理中心
// 3 点击左侧边栏(生态服务-应用服务)>>>点击AppGallery Connect
// 4 进入到以下页面

image.png

  • 步骤四:
// 1 点击我的项目>>>新建项目
// 2 数据处理位置选择中国并设置为默认
// 3 点击完成后并添加应用
// 4 注意:创建应用时如果想要自定义包名的话,定义的包名必须和新建项目时写的包名一致。
// 5 创建应用完成后,点击Next后,新建项目既可创建完成。

image.png

五、项目构建静态页面

登录注册页面

  • 效果图

image.png
image.png
结构:

// 一个页面:Login.etc
// 两个组件:
// 头部标题组件:titleComponent.ets
// 表单组件:InputComponent.ets

image.png

  • 代码
// Login.ets
import InputComponent from '../components/InputComponent';
import TitleComponent from '../components/TitleComponent';
import { typeNode } from '@ohos.arkui.node';
import { TESTTYPE } from '@ohos/hypium/src/main/Constant';

@Entry
@Component
struct Login {
  @State message: string = 'Login';
  // 倒计时
  @State countDown :number = 60
  timer :number=0
  @State isRegister:boolean= false

  // 发送验证码
  sendCode(){
    this.startCountDown()

  }
  // 开始倒计时
  startCountDown(){
  this.timer =   setInterval(()=>{
      this.countDown--
      if(this.countDown===0){
        this.countDown=60
        clearInterval(this.timer)
      }
    },1000)
  }


  build() {
      Column(){
        // title
        TitleComponent({title:"登录"})
        // login_content
        Stack({alignContent:Alignment.Top}){
          Image($r("app.media.Login_icon")).width(88).height(88).offset({y:-44}).zIndex(999)

       Column({space:10}){
            // emial
          InputComponent({title:"电子邮箱",inputIcon:$r("app.media.mail_icon"),placeholder:"请输入邮箱信息"})
            // pwd
          InputComponent({title:"密码",inputIcon:$r("app.media.pwd_icon"),placeholder:"请输入密码",inputType:InputType.Password})
            // VCode
          if(this.isRegister){
            Column(){
              Text("验证码").width("100%").textAlign(TextAlign.Start).fontWeight(500)
                .fontSize(16).fontColor(Color.Black).margin({bottom:14})
              Row(){
                TextInput({placeholder:"请输入验证码"})


                  .layoutWeight(1)
                  .backgroundColor(Color.Transparent)
                  .border({
                    width:1,
                    color:"#ff9b9b9b"

                  }).borderRadius(10)
                Button(this.countDown==60?"点击获取验证码":`${this.countDown}s`).fontSize("10").margin({left:10}).width(100).padding(0).onClick((event: ClickEvent) => {
                  if(this.countDown===60){
                    this.sendCode()
                  }else{
                    AlertDialog.show({
                      message:"正在获取验证码,请等待..."
                    })
                  }


                })

              }.width("100%").height(50)

            }
          }
            // login_btn
            Button(this.isRegister?"注册":"登录").width(228).backgroundColor("#ff09b19d").margin({top:50})
              .onClick(()=>{
                // 登录方法
              })
            // re_btn
         Row(){
           Text(this.isRegister?"去登录":"去注册").fontSize(12).onClick(()=>{
             this.isRegister= !this.isRegister
           })
           Text("|").padding({left:10,right:10})
           Text("忘记密码").fontSize(12)
         }.width("100%").layoutWeight(1).justifyContent(FlexAlign.Center)

       }.width("100%").height("100%").padding({left:14,right:14}).margin({top:44})

        }.width("90%").backgroundColor(Color.White).margin({top:44}).layoutWeight(1)
        .borderRadius(20)


      }.width("100%").height("100%").backgroundColor($r("app.color.page_Color"))
  }
}
// InputComponent.ets

@Component
export  default struct InputComponent {
  @Prop title:string
  @Prop inputIcon:Resource
  @Prop placeholder:string
  @Prop  inputType:InputType=InputType.Normal
  @State changeStatus:boolean =false
  build() {
    Column(){
      Text(this.title).width("100%").textAlign(TextAlign.Start).fontWeight(500)
        .fontSize(16).fontColor(Color.Black).margin({bottom:14})
      Row(){
        Image(this.inputIcon).width(40).aspectRatio(1)
        TextInput({placeholder:this.placeholder})
          .onFocus(()=>{
            // 聚焦
            this.changeStatus=true
            console.log("result>>>",this.changeStatus)
          })
          .onBlur(()=>{
            // 失去
            this.changeStatus=false
            console.log("result>>>",this.changeStatus)
          })

          .layoutWeight(1)
          .backgroundColor(Color.Transparent)
          .type(this.inputType)




      }.width("100%").height(50).padding({left:10,right:10}).borderRadius(10)
      .border({
        width:2,color:this.changeStatus?"#002884":Color.White
      })
    }
  }
}
// 页面标题组件 TitleComponent.ets

@Component
export  default struct TitleComponent {
  @Prop title :string
  build() {

    Row(){
      Image($r("app.media.Button_left")).width("44").height(41).objectFit(ImageFit.ScaleDown)
      Text(this.title).fontColor("#ff403f3f").fontWeight(700).fontSize(20).height(40)
      Text("")


    }.width("100%").justifyContent(FlexAlign.SpaceBetween).padding({left:20,right:20,top:12,bottom:12})
  }
}

主页框架及底部导航栏

  • 效果图(点击底部图标后,可以切换到对应页面并修改选中图标的底色。)

image.png
image.png

  • 功能点及编写思路
1 看着效果图像是多个页面编写而成的,其实就只有一个页面,通过tabs组件框架,嵌套其他组件从而形成多页面效果
2 框架编写思路:
整理和页面通用的数据并提取,在主页定义一个tabs组件,
分别定义5个页面的组件,和底部导航栏的组件
3 图标切换状态思路:
因为底部导航栏的数据是封装到了一个数组中,可以给每个对象定义一个ID属性,同时在主框架中定义一个
装饰器变量来监听tabs的onchange事件,因为ongchange事件会传递tab的下标,所有可以将传递的下标赋值给装饰器变量,
再将装饰器变量传递给底部导航栏图标组件,从而判断是否选中切换图标。

  • 结构:
  • image.png
实体类:
  BtnNavData
页面:
    MainPage
组件:
  CBtnNavImage
  DataStatistics
  Home
  My
  Wallet

代码:

// MainPage
import CBtnNavImage from './components/CBtnNavImage'
import { createBtnNavDataList,BtnNavData } from './model/BtnNavData'
@Entry
@Component
struct MainPage {
   @State btnNavItemid :number=0
  @State btnNavDataList:BtnNavData[] =createBtnNavDataList()
  // tabBar
  @Builder
  tabItemBar(item :BtnNavData){
     CBtnNavImage({btnNavData:item,isSelect:this.btnNavItemid})
  }
  build() {
    Tabs({barPosition:BarPosition.End}){
      ForEach(this.btnNavDataList,(item:BtnNavData,index)=>{
        TabContent(){
          Text(this.btnNavItemid.toString())

        }.tabBar(  this.tabItemBar(item))
      })

    }.onChange((index)=>{
      // 切换图标
      // console.log("result>>>>",index)
       if(index !=2){
         this.btnNavItemid =index
       }
    })
    .backgroundImage($r("app.media.Subtract"))
    .backgroundImagePosition(Alignment.BottomEnd)
    .backgroundImageSize({
      width:"100%",
      height:50
    })

  }
}
// BtnNavData
interface  IBtnNavData{
  selectIcon:Resource
  nowIcon:Resource
  title:string
  id:number

}
export   class BtnNavData{
  selectIcon:Resource
  nowIcon:Resource
  title:string
  id:number
  isQrcode:boolean

  constructor(obj:IBtnNavData,isQrcode=false) {
    this.selectIcon=obj.selectIcon
    this.nowIcon=obj.nowIcon
    this.title=obj.title
    this.id=obj.id
    this.isQrcode =isQrcode
  }
}

export  const createBtnNavDataList =():BtnNavData[]=>{
  return [
    new BtnNavData(
      {
        id:0,
        title:"首页",
        nowIcon:$r("app.media.home_icon_unselect"),
        selectIcon:$r("app.media.home_icon_select"),
      }
    ),
    new BtnNavData(
      {
        id:1,
        title:"数据展示",
        nowIcon:$r("app.media.data_icon_unselect"),
        selectIcon:$r("app.media.data_icon_select"),
      }
    ),
    new BtnNavData(
       {
        id:2,
        title:"扫一扫",
        nowIcon:$r("app.media.qrcode_icon"),
        selectIcon:$r("app.media.qrcode_icon"),

      },true
    ),
    new BtnNavData(
      {
        id:3,
        title:"钱包",
        nowIcon:$r("app.media.wallet_icon_unselect"),
        selectIcon:$r("app.media.wallet_icon_select"),

      }
    ),
    new BtnNavData(
      {
        id:4,
        title:"我的",
        nowIcon:$r("app.media.my_icon_unselect"),
        selectIcon:$r("app.media.my_icon_select"),

      }
    )

  ]
}
// CBtnNavImage
import { createBtnNavDataList,BtnNavData } from '../model/BtnNavData'
@Component

export default struct CBtnNavImage {
  @Prop btnNavData:BtnNavData
  @Prop isSelect :number =0
  build() {
    Column(){
      Image(this.isSelect ==this.btnNavData.id ?this.btnNavData.selectIcon:this.btnNavData.nowIcon).width(20).height(20)
        .offset({ y:this.btnNavData.isQrcode? -15 :0 })



    }.width("100%").justifyContent(FlexAlign.Center).height("100%")

  }
}
//  其余文件均为占位,并未编写

day01持续更新中…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1888472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

gif压缩工具免费在线哪个好?推荐4个实用压缩好物

压缩GIF动图相信不少朋友都会,但要想在压缩GIF的同时依旧最大限度地保持画质的清晰度,那可没那么简单! 不过想要实现高清压缩,也还是有许多妙招可用的!今天就给大家整理了4个我自用的压缩方法,保准能让gif…

WSL2安装ContOS7并更新gcc

目录 WSL2安装CentOS7下载安装包安装启动CentOS7 CentOS7更换国内源gcc从源码安装gcc卸载gcc CMake中使用gcc关于linux配置文件参考 WSL2安装CentOS7 Windows11官方WSL2已经支持Ubuntu、Open SUSE、Debian。但是没有centos,所以centos的安装方式略有不同。 下载安…

Pandas_DataFrame读写详解:案例解析(第24天)

系列文章目录 一、 读写文件数据 二、df查询数据操作 三、df增加列操作 四、df删除行列操作 五、df数据去重操作 六、df数据修改操作 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、 读写文…

强化学习-5 策略梯度、Actor-Critic 算法

文章目录 1 基于价值( value-based \text{value-based} value-based )算法的缺点2 策略梯度算法2.1 解释2.1.1 分母和分子相消2.1.2 对数函数的导数2.1.3 组合公式2.1.4 总结 3 REINFORCE算法4 策略梯度推导进阶4.1 平稳分布4.2 基于平稳分布的策略梯度…

LeetCode题练习与总结:二叉树的后序遍历--145

一、题目描述 给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。 示例 1: 输入:root [1,null,2,3] 输出:[3,2,1]示例 2: 输入:root [] 输出:[]示例 3: 输入&#xff1a…

关于批量采集1688商品主图及链接的方式:软件采集/1688官方API接口数据采集

关于批量采集,我们通常用到的是软件 采集,或者通过1688官方API数据采集的形式:用户输入一组1688商品ID,一行一个,流程会自动逐个打开对应的1688商品详情页,采集主图的所有链接。 结果保存为表格的一行&…

人工智能-NLP简单知识汇总01

人工智能-NLP简单知识汇总01 1.1自然语言处理的基本概念 自然语言处理难点: 语音歧义句子切分歧义词义歧义结构歧义代指歧义省略歧义语用歧义 总而言之:!!语言无处不歧义 1.2自然语言处理的基本范式 1.2.1基于规则的方法 通…

JDBC【封装工具类、SQL注入问题】

day54 JDBC 封装工具类01 创建配置文件 DBConfig.properties driverNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/qnz01?characterEncodingutf8&serverTimezoneUTC usernameroot passwordroot新建配置文件,不用写后缀名 创建工具类 将变…

【Linux】TCP协议【下三】{面向字节流/粘包问题/TCP异常情况/文件和Socket}

文章目录 7.面向字节流TCP(传输控制协议)和UDP(用户数据报协议) 8.粘包问题9.TCP异常情况10.再谈文件和socket的关系 7.面向字节流 创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;一个链接一对发收缓…

day09了 加油

浅拷贝 指向同一个地址空间 右边不可取地址 左边一定是到了具体的位置 右值引用std&#xff1a;&#xff1a; move 相信大家默认构造函数都没有问题&#xff0c;所以就不贴例子了 浅拷贝构造函数 只负责复制地址&#xff0c;而不是真的把完整的内存给它 #include <iostre…

Qt——升级系列(Level Seven):事件、文件

目录 Qt事件 事件介绍 事件的处理 按键事件 鼠标事件 定时器 事件分发器 事件过滤器 Qt文件 Qt文件概述 输入输出设备类 文件读写类 文件和目录信息类 Qt事件 事件介绍 事件是应⽤程序内部或者外部产⽣的事情或者动作的统称。在 Qt 中使⽤⼀个对象来表⽰⼀个事件。所有的 Qt …

Linux修炼之路之进程概念,fork函数,进程状态

目录 一&#xff1a;进程概念 二&#xff1a;Linux中的进程概念 三&#xff1a;用getpid(),getppid()获取该进程的PID,PPID 四&#xff1a;用fork()来创建子进程 五&#xff1a;操作系统学科的进程状态 六&#xff1a;Linux中的进程状态 接下来的日子会顺顺利利&#xf…

WordPress网站添加插件和主题时潜在危险分析

WordPress 最初只是一个简单的博客软件&#xff0c;现在据估计为全球前 1000 万个网站中的 30% 提供支持。WordPress受欢迎的因素之一是可以轻松创建插件和主题来扩展它并提供比默认设置更多的功能。 目前&#xff0c;WordPress 网站列出了 56,000 多个插件以及数千个主题。插件…

提升用户体验之requestAnimationFrame实现前端动画

requestAnimationFrame是什么 MDN官方解释 解析这段话&#xff1a; 1、那么浏览器重绘是指什么呢&#xff1f; ——大多数电脑的显示器刷新频率是60Hz&#xff0c;1000ms/6016.66666667ms的时间刷新一次 2、重绘之前调用指定的回调函数更新动画&#xff1f; ——requestAnima…

机器学习辅助的乙醇浓度检测

目录 1.为什么要机器学习 2. 神经网络一般组成 3.BP神经网络工作过程 4.评价指标 5.实操代码 1.为什么要用机器学习 人工分析大量的谐振模式&#xff0c;建立各种WGM的响应与未知目标之间的关系&#xff0c;是一个很大的挑战。机器学习(ML)能够自行识别全谱的全部特征。作为…

Python深度理解系列之【排序算法——冒泡排序】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️木道寻的主页 文章目录 &#x1f525;前言&#x1f680;冒泡排序python实现算法实现图形化算法展示 ⭐️⭐️⭐️总结 &#x1f525;前…

ONLYOFFICE8.1版本桌面编辑器简单测评

ONLYOFFICE官网链接&#xff1a;在线PDF查看器和转换器 | ONLYOFFICE ONLYOFFICE介绍&#xff1a;https://www.onlyoffice.com/zh/office-suite.aspx OnlyOffice 是一款免费且开源的 Office 协作办公套件&#xff0c;支持桌面端和移动端等多平台&#xff0c;由一家领先的 IT 公…

OpenStack开源虚拟化平台(二)

目录 三、对象存储服务Swift&#xff08;一&#xff09;Swift特性&#xff08;二&#xff09;应用场景&#xff08;三&#xff09;Swift主要组件&#xff08;四&#xff09;Swift基本原理&#xff08;五&#xff09;实例分析 四、镜像服务Glance&#xff08;一&#xff09;Glan…

如何在 Java 应用中使用 Jedis 客户端库来实现 Redis 缓存的基本操作

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…