简言:
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
项目构建静态页面
钱包页面
- 效果图
- 结构:
主页面:Wallet.ets
子页面:addCard.ets
组件:
BankCardComponent 银行卡片
TitleComponent 顶部标题
- 编写思路:
// 钱包页面和主页页面效果类似,复制其修改部分既可。
- 代码
// 页面三:钱包 Wallet
import { BankCardComponent } from '../../components/BankCardComponent'
import TitleComponent from '../../components/TitleComponent'
@Component
export default struct Wallet {
build() {
Column(){
TitleComponent({title:"钱包",is_addIcon:true})
Column(){
// Text("您好,").width("100%").fontWeight(500)
// Text("欢迎回来!").width("100%").fontWeight(500).fontSize(18).margin({top:5,bottom:15})
// card
Swiper(){
BankCardComponent()
BankCardComponent()
}.loop(true)
.autoPlay(true)
.indicator(
Indicator.dot().
color(Color.White)
.selectedColor(Color.White)
.selectedItemWidth(20)
).borderRadius(20)
// 功能分类
Text("最近联系").width("100%").fontWeight(500).fontSize(18).margin({top:5,bottom:15}).margin({top:30,bottom:20})
Row({space:20}){
Image($r("app.media.avatar_icon")).width(50).borderRadius(8)
Image($r("app.media.avatar_icon")).width(50).borderRadius(8)
Image($r("app.media.avatar_icon")).width(50).borderRadius(8)
Image($r("app.media.avatar_icon")).width(50).borderRadius(8)
}.width("100%")
// 功能分类
Text("交易信息").width("100%").fontWeight(500).fontSize(18).margin({top:5,bottom:15}).margin({top:30,bottom:20})
Column(){
List(){
ForEach((Array.from({length:10})),()=>{
ListItem(){
Row(){
Image($r("app.media.avatar_icon")).width(36).borderRadius(18).margin({left:5,right:5})
Column(){
Text("便利店").width("100%").fontSize(14).fontColor("#666")
Text("2024年6月29日").width("100%").fontSize(12).fontColor("#999")
}.layoutWeight(1)
Text("¥1250.50").backgroundColor("#ffffe0e0").borderRadius(20).width(100).height(35)
.textAlign(TextAlign.Center).fontSize(12).fontColor("#f00")
}.width("100%").height(50).backgroundColor("#fffafafa").borderRadius(10).margin({bottom:10})
}
})
}
}.width("100%").layoutWeight(1)
}.width("100%").layoutWeight(1).padding({left:20,right:20})
}.width("100%").height("100%").backgroundColor("#ffffffff")
}
}
// 添加银行卡 子页面:AddCard
import InputComponent from '../../components/InputComponent';
import TitleComponent from '../../components/TitleComponent';
@Extend(Text)
function titleTextStyle(){
.width("100%").fontWeight(500).fontSize(18).margin({top:30,bottom:20})
}
@Entry
@Component
struct AddCard {
@State message: string = 'Hello World';
build() {
Column(){
// titile
TitleComponent({title:"添加新的银行卡",routerUrl:'',is_icon:true})
// content
Column({space:30}){
Text("卡片信息").titleTextStyle()
InputComponent({title:'银行卡号',placeholder:'XXXXXXXX XXX XXXXXX',isInputIcon:false})
InputComponent({title:'持卡人姓名',placeholder:'请输入持卡人姓名',isInputIcon:false})
Row({space:10}){
InputComponent({title:'CCV',placeholder:'2533',isInputIcon:false}).layoutWeight(1)
InputComponent({title:'到期时间',placeholder:'30-06-2024',isInputIcon:false}).layoutWeight(1)
}
Button("下一步").width(228).backgroundColor("#ff09b19d").margin({top:50})
}.width("100%").height("100%").padding({left:20,right:20})
}.width("100%").height("100%").backgroundImage($r("app.media.pageBg"))
}
}
// 银行卡片组件:BankCardComponent
@Component
export struct BankCardComponent {
build() {
Column(){
Row(){
Text("中国银行").layoutWeight(1).fontColor(Color.White).fontSize(14).fontWeight(500)
Image($r("app.media.card_icon")).width(36)
}
Text(){
Span("¥").fontSize(12)
Span("25,230,00").fontSize(24).fontWeight(700)
}.width("100%").fontColor(Color.White).margin({top:20})
Row(){
Text("xxxxxxxxxx xx xxxxx ").layoutWeight(1).fontColor(Color.White).fontSize(14).fontWeight(500)
Text("26/24").fontColor(Color.White).fontSize(12).padding({right:40})
}.margin({top:15})
}.width("100%").height(150).backgroundColor("#ff09d7d3").padding(20)
}
}
// 页面标题组件: TitleComponent
import text from '@ohos.graphics.text'
import router from '@ohos.router'
@Component
export default struct TitleComponent {
@Prop title :string
@Prop is_icon:boolean
@Prop is_addIcon:boolean
@Prop routerUrl:string
@Prop titleColor:string
build() {
Row(){
if(this.is_icon){
Image($r("app.media.Button_left")).width("44").height(30).objectFit(ImageFit.ScaleDown).borderRadius(5)
.onClick(()=>{
router.back()
})
}
Text(this.title).fontColor(this.titleColor).fontWeight(700).fontSize(20).height(40).layoutWeight(1).textAlign(TextAlign.Center)
if(this.is_addIcon){
Text("+").fontColor(Color.White).fontSize(25).fontWeight(500).border({width:2})
.borderRadius(30).width(25).height(25).fontColor(Color.Black).lineHeight(25).textAlign(TextAlign.Center).onClick(()=>{
router.pushUrl({
url:'pages/bank/AddCard'
})
})
}
}.width("100%").justifyContent(FlexAlign.SpaceBetween).padding({left:20,right:20,top:12,bottom:12})
}
}
个人页面
- 效果图
- 结构
组件:
BankCardComponent 银行卡片
TitleComponent 顶部标题
InputDateComponent 选择日期弹框
InputComponent 普通表单输入框
页面:
My 个人主页
InfoEdit 个人信息修改页
QrCodePage 个人信息二维码生成页
工具类:tools
- 代码
// 页面四:个人信息页
import TitleComponent from '../../components/TitleComponent'
import router from '@ohos.router'
import { Router } from '@kit.ArkUI'
@Component
export default struct My {
build() {
Column(){
TitleComponent({title:"个人资料",titleColor:"#ffff"})
Stack({alignContent:Alignment.Start}){
Column().width("100%").height(120)
.backgroundColor("#ffc3f6e1")
.margin({top:50}).borderRadius(20).shadow({radius:10,color:"#fff"})
Column(){
Image($r("app.media.user")).width(66).height(66).borderRadius(22)
.border({
width:5,
color:'#ff09b06d',
style:BorderStyle.Solid
}).shadow({radius:10,color:"#fff"})
Text("追风的少年").offset({x:80,y:-30}).width("100%")
Text("财富的意义,在于分享与贡献,而非单纯的积累。").fontSize(14).fontColor("#ff969191").margin({top:10})
.offset({y:-10}).margin({right:10})
}.width("100%").alignItems(HorizontalAlign.Start).margin({left:10})
Image($r("app.media.right_i")).height(20).offset({
y:60,x:270
})
}.width("100%").padding({left:30,right:30})
Row(){
Image($r("app.media.edit_icon")).height(30).margin({right:20})
Text("编辑个人信息").layoutWeight(1).fontSize(14)
Image($r("app.media.right_icon")).height(25)
}.height(40).padding({left:5,right:10}).backgroundColor("#fff").margin(20)
.borderRadius(10).shadow({radius:20,color:"#ff70e7d5"}).onClick(()=>{
router.pushUrl({
url:"pages/info/InfoEdit"
})
})
Row(){
Image($r("app.media.qrcode_icon_external")).height(25).margin({left:5,right:30})
Text("个人二维码").layoutWeight(1).fontSize(14)
Image($r("app.media.right_icon")).height(25)
}.height(40).padding({left:5,right:10}).backgroundColor("#fff").margin(20)
.borderRadius(10).shadow({radius:20,color:"#ff70e7d5"}).onClick(()=>{
router.pushUrl({
url :'pages/info/QrCodePage'
})
})
}.width("100%").height("100%").backgroundImage($r("app.media.myPageBg"))
.backgroundImageSize({width:"100%",height:"100%"})
}
}
// 个人信息修改页
import InputComponent from '../../components/InputComponent';
import InputDateComponent from '../../components/InputDateComponent';
import TitleComponent from '../../components/TitleComponent';
@Extend(Text)
function titleTextStyle(){
.width("100%").fontWeight(500).fontSize(18).margin({top:30,bottom:20})
}
@Entry
@Component
struct InfoEdit {
@State message: string = 'Hello World';
selectedDate: Date = new Date("2010-1-1")
build() {
Column(){
// titile
TitleComponent({title:"编辑个人信息",routerUrl:'',is_icon:true})
// content
Column({space:30}){
Text("个人信息").titleTextStyle()
InputComponent({title:'姓名',placeholder:'请输入您的姓名',isInputIcon:false})
InputComponent({title:'联系电话',placeholder:'请输入你的手机号码',isInputIcon:false})
Row({space:10}){
InputComponent({title:'性别',placeholder:'2533',isInputIcon:false}).layoutWeight(1)
InputDateComponent ({title:'出生日期',placeholder:'30-06-2024',isInputIcon:false}).layoutWeight(1)
}
Button("下一步").width(228).backgroundColor("#ff09b19d").margin({top:50})
}.width("100%").height("100%").padding({left:20,right:20})
}.width("100%").height("100%").backgroundImage($r("app.media.pageBg"))
}
}
// 个人信息二维码生成页
import TitleComponent from '../../components/TitleComponent';
import { randomColor } from '../../util/tools';
@Entry
@Component
struct QrCodePage {
@State message: string = 'Hello World';
@State BgColor :string = "#ffc2f17d"
build() {
Column() {
// titile
TitleComponent({title:"",routerUrl:'',is_icon:true})
QRCode("1").margin({top:40}).height(200).aspectRatio(1).backgroundColor(Color.Transparent)
Blank()
Row({space:20}){
Text("换个样式").onClick(()=>{
this.BgColor = randomColor()
})
Text("|")
Text("保存图片")
}.width("100%").justifyContent(FlexAlign.Center).margin({bottom:20})
}
.height('100%').backgroundColor(this.BgColor)
.width('100%')
}
}
// 日期选择框
@Component
export default struct InputDateComponent {
@Prop title:string
@Prop inputIcon:Resource
@Prop placeholder:string
@Prop inputType:InputType=InputType.Normal
@State changeStatus:boolean =false
@Prop isInputIcon:boolean = true
selectedDate: Date = new Date()
build() {
Column(){
Text(this.title).width("100%").textAlign(TextAlign.Start).fontWeight(500)
.fontSize(16).fontColor(Color.Black).margin({bottom:14})
Row(){
if (this.isInputIcon) {
Image(this.inputIcon).width(40).aspectRatio(1)
}
TextInput({placeholder:this.placeholder})
.onClick(()=>{
DatePickerDialog.show({
start: new Date("1970-1-1"),
end: new Date("2100-12-31"),
selected: this.selectedDate,
showTime:true,
useMilitaryTime:false,
// disappearTextStyle: {color: Color.Pink, font: {size: '22fp', weight: FontWeight.Bold}},
// textStyle: {color: '#ff00ff00', font: {size: '18fp', weight: FontWeight.Normal}},
// selectedTextStyle: {color: '#ff182431', font: {size: '14fp', weight: FontWeight.Regular}},
onDateAccept: (value: Date) => {
// 通过Date的setFullYear方法设置按下确定按钮时的日期,这样当弹窗再次弹出时显示选中的是上一次确定的日期
this.selectedDate = value
console.info("DatePickerDialog:onDateAccept()" + value.toString())
},
onCancel: () => {
console.info("DatePickerDialog:onCancel()")
},
onDateChange: (value: Date) => {
console.info("DatePickerDialog:onDateChange()" + value.toString())
}
})
})
.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
})
}
}
}
// 普通输入框
@Component
export default struct InputComponent {
@Prop title:string
@Prop inputIcon:Resource
@Prop placeholder:string
@Prop inputType:InputType=InputType.Normal
@State changeStatus:boolean =false
@Prop isInputIcon:boolean = true
build() {
Column(){
Text(this.title).width("100%").textAlign(TextAlign.Start).fontWeight(500)
.fontSize(16).fontColor(Color.Black).margin({bottom:14})
Row(){
if (this.isInputIcon) {
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":"#ffcbcccd"
})
}
}
}
// 随机颜色生成方法
// 十六进制的随机颜色
export function randomColor():string{
let color:string = "#"
let colors:string[] = [
"a","b", "c","d", "e","f",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
]
for (let i = 0; i <8 ; i++) {
color+=colors[Math.floor(Math.random()*15)]
}
return color
}
支付页面
- 效果图
- 结构
页面:PayPage
自定义弹框组件:PayCustomDialogExample
- 代码
// 付款页
import TitleComponent from '../../components/TitleComponent';
import PayCustomDialogExample from './PayCustomDialogExample';
@Entry
@Component
struct PayPage {
dialogController: CustomDialogController = new CustomDialogController({
builder: PayCustomDialogExample(),
alignment:DialogAlignment.Bottom,
customStyle:true
})
onPageShow(): void {
this.dialogController.open()
}
@State message: string = 'Hello World';
build() {
Column() {
TitleComponent({title:"支付",is_icon:true})
}
.height('100%')
.width('100%').backgroundColor("#ff5f5d5d")
}
}
// 付款弹框组件
import InputComponent from '../../components/InputComponent'
@CustomDialog
export default struct PayCustomDialogExample {
controller: CustomDialogController = new CustomDialogController({
builder: PayCustomDialogExample({}),
})
build() {
Column() {
Text("付款给").border({width:{bottom:1},color:'#ffe2e2e2'}).width("100%").lineHeight(20)
.textAlign(TextAlign.Center).padding({top:10,bottom:10})
.fontWeight(500).fontColor("#ff044a6e")
Stack({alignContent:Alignment.Top}){
Column().width("100%").height(80).shadow({radius:60,color:"#ffcfcfcf"}).borderRadius(20).margin({top:50})
Column({space:5}){
Image($r("app.media.HOS")).height(50).borderRadius(10).aspectRatio(2).margin({top:20})
Text("HarmonyOS APP应用开发").fontSize(14).fontWeight(700)
Text("2024-06-30").fontSize(12).fontColor("#666")
}
}.width("100%").padding({right:50,left:50,bottom:20})
Text("支付账户").fontWeight(700).fontSize(18).height(40)
.width("100%").padding({left:20})
Row(){
Column().width(50).backgroundColor("#0ff").height(30).margin(5).borderRadius(5)
Column(){
Text("中国银行储蓄卡").fontColor("#ff033048").fontSize(14).width("100%")
Text("xxxxxx xxxxx xxxx ").fontColor("#999").fontSize(12).width("100%")
}.layoutWeight(1)
Image($r("app.media.right_icon")).width(20)
}.height(40).margin({left:20,right:20}).shadow({radius:60,color:"#ffcfcfcf"}).borderRadius(10)
Text("支付金额").fontWeight(700).fontSize(18).height(40)
.width("100%").padding({left:20}).margin({top:10,bottom:10})
Text("¥155.55").fontWeight(700).fontSize(24).height(40)
Column({space:10}){
InputComponent({title:'用户订单姓名',placeholder:'输入你的名称'})
InputComponent({title:'用户订单电话号码',placeholder:'输入您的电话号码'})
}.width("100%").padding({left:20,right:20})
Button("下一步").width(228).backgroundColor("#ff09b19d").margin({top:50})
}.height("100%").width("100%").margin({top:80}).borderRadius({topLeft:20,topRight:20}).backgroundColor(Color.White)
}
}
day02 项目结构基本搭建完成,静态页面基本编写完成