接下来我们继续学习如何用ArkUI来开发一个购物应用程序(下半部分)
底部组件是由一个横向的图片列表组成,iconPath是底部初始状态下的3张图片路径数组。遍历iconPath数组,使用Image组件设置图片路径并添加到List中,给每个Image组件设置点击事件,点击更换底部3张图片。在HomeBottom中,iconPath使用的是@State修饰,当iconPath数组内容变化时,页面组件有使用到的地方都会随之发生变化。
在MyPage.ets文件中新建MyTransList组件和MoreGrid组件,MyTransList组件代码如下:
@Component
struct MyTransList {
private imageItems: ImageItem[] = getTrans()
build() {
Column() {
Text('My Transaction')
.fontSize(20)
.margin({ left: 10 })
.width('100%')
.height(30)
Row() {
List() {
ForEach(this.imageItems, item => {
ListItem() {
DataItem({ imageItem: item })
}
}, item => item.id.toString())
}
.height(70)
.width('100%')
.align(Alignment.Top)
.margin({ top: 5})
.listDirection(Axis.Horizontal)
}
}
.height(120)
}
}
MoreGrid组件代码如下:
@Component
struct MoreGrid {
private gridRowTemplate: string = ''
private imageItems: ImageItem[] = getMore()
private heightValue: number
aboutToAppear() {
var rows = Math.round(this.imageItems.length / 3);
this.gridRowTemplate = '1fr '.repeat(rows);
this.heightValue = rows * 75 ;
}
build() {
Column() {
Text('More')
.fontSize(20)
.margin({ left: 10 })
.width('100%')
.height(30)
Scroll() {
Grid() {
ForEach(this.imageItems, (item: ImageItem) => {
GridItem() {
DataItem({ imageItem: item })
}
}, (item: ImageItem) => item.id.toString())
}
.rowsTemplate(this.gridRowTemplate)
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.height(this.heightValue)
}
.padding({ left: 16, right: 16 })
}
.height(400)
}
}
在MyTransList和MoreGrid组件中都包含子组件DataItem,为避免的重复代码,可以把多次要用到的结构体组件化,这里的结构体就是图片加上文本的上下结构体,DataItem组件内容如下:
@Component
struct MenuItem {
private menu: Menu
build() {
Column() {
Text(this.menu.title)
.fontSize(15)
Text(this.menu.num+'')
.fontSize(13)
}
.height(50)
.width(80)
.margin({left: 8,right:8})
.alignItems(HorizontalAlign.Start)
.backgroundColor(Color.White)
}
}
实现购物车页签
主界面购物车页签主要由下面三部分组成:
- 顶部的Text组件。
- 中间的List组件,其中List组件的item是一个水平的布局内包含一个toggle组件,一个Image组件和一个垂直布局,其item中的垂直布局是由2个Text组件组成。
- 底部一个水平布局包含两个Text组件。
构建一个购物车页签,给商品列表的每个商品设置一个单选框,可以选中与取消选中,底部Total值也会随之增加或减少,点击Check Out时会触发弹窗。下面我们来完成ShoppingCart页签。
在pages目录下面新建一个Page ,命名为ShoppingCart.。在ShoppingCart.ets文件中添加入口组件(ShoppingCart),并导入需要使用到的数据实体类、方法和组件。ShoppingCart组件代码如下:
@Entry
@Component
export struct ShoppingCart {
@Provide totalPrice : number =0
private goodsItems: GoodsData[] = initializeOnStartup()
build() {
Column() {
Column() {
Text('ShoppingCart')
.fontColor(Color.Black)
.fontSize(25)
.margin({ left: 60,right:60 })
.align(Alignment.Center)
}
.backgroundColor('#FF00BFFF')
.width('100%')
.height(30)
ShopCartList({ goodsItems: this.goodsItems });
ShopCartBottom()
}
.alignItems(HorizontalAlign.Start)
}
}
新建ShopCartList组件用于存放购物车商品列表,ShopCartList组件代码如下
@Component
struct ShopCartList {
private goodsItems: GoodsData[]
build() {
Column() {
List() {
ForEach(this.goodsItems, item => {
ListItem() {
ShopCartListItem({ goodsItem: item })
}
}, item => item.id.toString())
}
.height('100%')
.width('100%')
.align(Alignment.Top)
.margin({top: 5})
}
.height(570)
}
}
ShopCartListItem组件代码如下:
@Component
struct ShopCartListItem {
@Consume totalPrice: number
private goodsItem: GoodsData
build() {
Row() {
Toggle({type: ToggleType.Checkbox})
.width(10)
.height(10)
.onChange((isOn:boolean) => {
if(isOn){
this.totalPrice +=parseInt(this.goodsItem.price+'',0)
}else{
this.totalPrice -= parseInt(this.goodsItem.price+'',0)
}
})
Image(this.goodsItem.imgSrc)
.objectFit(ImageFit.ScaleDown)
.height(100)
.width(100)
.renderMode(ImageRenderMode.Original)
Column() {
Text(this.goodsItem.title)
.fontSize(14)
Text('¥' + this.goodsItem.price)
.fontSize(14)
.fontColor(Color.Red)
}
}
.height(100)
.width(180)
.margin({left: 20})
.alignItems(VerticalAlign.Center)
.backgroundColor(Color.White)
}
}
在ShopCartListItem中使用Toggle的单选框类型来实现每个item的选择和取消选择,在Toggle的onChage事件中来改变totalPrice的数值。
新建ShopCartBottom组件,ShopCartBottom组件代码如下:
@Component
struct ShopCartBottom {
@Consume totalPrice: number
build() {
Row() {
Text('Total: ¥'+this.totalPrice)
.fontColor(Color.Red)
.fontSize(18)
.margin({left:20})
.width(150)
Text('Check Out')
.fontColor(Color.Black)
.fontSize(18)
.margin({right:20,left:100})
.onClick(()=>{
prompt.showToast({
message: 'Checking Out',
duration: 10,
bottom:100
})
})
}
.height(30)
.width('100%')
.backgroundColor('#FF7FFFD4')
.alignItems(VerticalAlign.Bottom)
}
}
实现我的页签
我的页签主要由下面四部分组成:
- 顶部的水平布局。
- 顶部下面的文本加数字的水平List。
- My Transactio模块,图片加文本的水平List。
- More模块,图片加文本的Grid。
构建主页我的页签,主要可以划分成下面几步:
- 在pages目录下面新建一个Page 命名为MyPage
- 在MyPage.ets文件中添加入口组件(MyInfo)
MyInfo组件内容如下:
import {getMenu,getTrans,getMore} from '../model/GoodsDataModels'
import {Menu, ImageItem} from '../model/Menu'
@Entry
@Component
export struct MyInfo {
build() {
Column() {
Row(){
Image($rawfile('nav/icon-user.png'))
.margin({left:20})
.objectFit(ImageFit.Cover)
.height(50)
.width(50)
.renderMode(ImageRenderMode.Original)
.margin({left:40,right:40})
Column(){
Text('John Doe')
.fontSize(15)
Text('Member Name : John Doe >')
}
.height(60)
.margin({left:40,top:10})
.alignItems(HorizontalAlign.Start)
}
TopList()
MyTransList()
MoreGrid()
}
.alignItems(HorizontalAlign.Start)
.width('100%')
.flexGrow(1)
}
}
入口组件中还包含TopList,MyTransList和MoreGrid三个子组件。代码如下:
@Component
struct TopList {
private menus: Menu[] = getMenu()
build() {
Row() {
List() {
ForEach(this.menus, item => {
ListItem() {
MenuItem({ menu: item })
}
}, item => item.id.toString())
}
.height('100%')
.width('100%')
.margin({top: 5})
.edgeEffect(EdgeEffect.None)
.listDirection(Axis.Horizontal)
}
.width('100%')
.height(50)
}
}
@Component
struct MyTransList {
private imageItems: ImageItem[] = getTrans()
build() {
Column() {
Text('My Transaction')
.fontSize(20)
.margin({ left: 10 })
.width('100%')
.height(30)
Row() {
List() {
ForEach(this.imageItems, item => {
ListItem() {
DataItem({ imageItem: item })
}
}, item => item.id.toString())
}
.height(70)
.width('100%')
.align(Alignment.Top)
.margin({ top: 5})
.listDirection(Axis.Horizontal)
}
}
.height(120)
}
}
@Component
struct MoreGrid {
private gridRowTemplate: string = ''
private imageItems: ImageItem[] = getMore()
private heightValue: number
aboutToAppear() {
var rows = Math.round(this.imageItems.length / 3);
this.gridRowTemplate = '1fr '.repeat(rows);
this.heightValue = rows * 75 ;
}
build() {
Column() {
Text('More')
.fontSize(20)
.margin({ left: 10 })
.width('100%')
.height(30)
Scroll() {
Grid() {
ForEach(this.imageItems, (item: ImageItem) => {
GridItem() {
DataItem({ imageItem: item })
}
}, (item: ImageItem) => item.id.toString())
}
.rowsTemplate(this.gridRowTemplate)
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.height(this.heightValue)
}
.padding({ left: 16, right: 16 })
}
.height(400)
}
}
实现商品详情页面
商品详情页面主要由下面五部分组成:
- 顶部的返回栏。
- Swiper组件。
- 中间多个Text组件组成的布局。
- 参数列表。
- 底部的Buy。
把上面每一部分都封装成一个组件,然后再放到入口组件内,当点击顶部返回图标时返回到主页面的商品列表页签,点击底部Buy时,会触发进度条弹窗。
在pages目录下面新建一个Page, 命名为ShoppingDetail。在ShoppingDetail.ets文件中创建入口组件,组件内容如下:
import router from '@system.router';
import {ArsData} from '../model/ArsData'
import {getArs,getDetailImages} from '../model/GoodsDataModels'
import prompt from '@system.prompt';
@Entry
@Component
struct ShoppingDetail {
private arsItems: ArsData[] = getArs()
private detailImages: string[] = getDetailImages()
build() {
Column() {
DetailTop()
Scroll() {
Column() {
SwiperTop()
DetailText()
DetailArsList({ arsItems: this.arsItems })
Image($rawfile('computer/computer1.png'))
.height(220)
.width('100%')
.margin({top:30})
Image($rawfile('computer/computer2.png'))
.height(220)
.width('100%')
.margin({top:30})
Image($rawfile('computer/computer3.png'))
.height(220)
.width('100%')
.margin({top:30})
Image($rawfile('computer/computer4.png'))
.height(220)
.width('100%')
.margin({top:30})
Image($rawfile('computer/computer5.png'))
.height(220)
.width('100%')
.margin({top:30})
Image($rawfile('computer/computer6.png'))
.height(220)
.width('100%')
.margin({top:30})
}
.width('100%')
.flexGrow(1)
}
.scrollable(ScrollDirection.Vertical)
DetailBottom()
}
.height(630)
}
}
顶部DetailTop组件代码如下:
@Component
struct DetailTop{
build(){
Column(){
Row(){
Image($rawfile('detail/icon-return.png'))
.height(20)
.width(20)
.margin({ left: 20, right: 250 })
.onClick(() => {
router.push({
uri: "pages/HomePage"
})
})
}
.width('100%')
.height(25)
.backgroundColor('#FF87CEEB')
}
.width('100%')
.height(30)
}
}
SwiperTop组件代码如下:
@Component
struct SwiperTop{
build() {
Column() {
Swiper() {
Image($rawfile('computer/computer1.png'))
.height(220)
.width('100%')
Image($rawfile('computer/computer2.png'))
.height(220)
.width('100%')
Image($rawfile('computer/computer3.png'))
.height(220)
.width('100%')
Image($rawfile('computer/computer4.png'))
.height(220)
.width('100%')
Image($rawfile('computer/computer5.png'))
.height(220)
.width('100%')
Image($rawfile('computer/computer6.png'))
.height(220)
.width('100%')
}
.index(0)
.autoPlay(true)
.interval(3000)
.indicator(true)
.loop(true)
.height(250)
.width('100%')
}
.height(250)
.width('100%')
}
}
DetailText组件代码如下:
@Component
struct DetailText{
build() {
Column() {
Row(){
Image($rawfile('computer/icon-promotion.png'))
.height(30)
.width(30)
.margin({left:10})
Text('Special Offer: ¥9999')
.fontColor(Color.White)
.fontSize(20)
.margin({left:10})
}
.width('100%')
.height(35)
.backgroundColor(Color.Red)
Column(){
Text('New Arrival: HUAWEI MateBook X Pro 2021')
.fontSize(15)
.margin({left:10})
.alignSelf(ItemAlign.Start)
Text('13.9-Inch, 11th Gen Intel® Core™ i7, 16 GB of Memory, 512 GB of Storage, Ultra-slim Business Laptop, 3K FullView Display, Multi-screen Collaboration, Emerald Green')
.fontSize(10)
.margin({left:10})
Row(){
Image($rawfile('nav/icon-buy.png'))
.height(15)
.width(15)
.margin({left:10})
//TODO 暂不支持跑马灯组件,用Text代替
Text('Limited offer')
.fontSize(10)
.fontColor(Color.Red)
.margin({left:100})
}
.backgroundColor(Color.Pink)
.width('100%')
.height(25)
.margin({top:10})
Text(' Shipment: 2-day shipping')
.fontSize(13)
.fontColor(Color.Red)
.margin({left:10,top:5})
.alignSelf(ItemAlign.Start)
Text(' Ship To: Hubei,Wuhan,China')
.fontSize(13)
.fontColor(Color.Red)
.margin({left:10,top:5})
.alignSelf(ItemAlign.Start)
.onClick(()=>{
prompt.showDialog({title:'select address',})
})
Text('Guarantee: Genuine guaranteed')
.fontSize(13)
.margin({left:10,top:5})
.alignSelf(ItemAlign.Start)
}
.height(150)
.width('100%')
}
.height(160)
.width('100%')
}
}
DetailArsList组件代码如下:
@Component
struct DetailArsList{
private arsItems: ArsData[]
build() {
Scroll() {
Column() {
List() {
ForEach(this.arsItems, item => {
ListItem() {
ArsListItem({ arsItem: item })
}
}, item => item.id.toString())
}
.height('100%')
.width('100%')
.margin({ top: 5 })
.listDirection(Axis.Vertical)
}
.height(200)
}
}
}
ArsListItem组件代码如下:
@Component
struct ArsListItem {
private arsItem: ArsData
build() {
Row() {
Text(this.arsItem.title+" :")
.fontSize(11)
.margin({left:20})
.flexGrow(1)
Text( this.arsItem.content)
.fontSize(11)
.margin({right:20})
}
.height(14)
.width('100%')
.backgroundColor(Color.White)
}
}
DetailBottom组件代码如下:
@Component
struct DetailBottom{
@Provide
private value : number=1
dialogController : CustomDialogController = new CustomDialogController({
builder: DialogExample({action: this.onAccept}),
cancel: this.existApp,
autoCancel: true
});
onAccept() {
}
existApp() {
}
build(){
Column(){
Text('Buy')
.width(40)
.height(25)
.fontSize(20)
.fontColor(Color.White)
.onClick(()=>{
this.value=1
this.dialogController.open()
})
}
.alignItems(HorizontalAlign.Center)
.backgroundColor(Color.Red)
.width('100%')
.height(40)
}
}
DialogExample自定义弹窗组件代码如下:
@CustomDialog
struct DialogExample {
@Consume
private value : number
controller: CustomDialogController;
action: () => void;
build() {
Column() {
Progress({value: this.value++ >=100?100:this.value, total: 100, style: ProgressStyle.Eclipse})
.height(50)
.width(100)
.margin({top:5})
}
.height(60)
.width(100)
}
}
添加资源文件
程序中所用到的资源文件都放置到resources\rawfile目录下。
删除index.ets
因为程序的入口文件已经改为了HomePage.ets文件,因此需要删除Index.ets文件。
HomePage.ets文件重新命名
把HomePage.ets文件重新命名为Index.ets文件。
程序运行效果
以上内容是介绍了如何用ArkUI来开发一个购物应用程序全部教程
为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了几套最新版的HarmonyOS NEXT学习资源
获取完整版高清学习路线,请点击→《HarmonyOS教学视频》
HarmonyOS教学视频
鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程
鸿蒙生态应用开发白皮书V2.0PDF:
获取白皮书:请点击→《鸿蒙生态应用开发白皮书V2.0PDF》
鸿蒙 (Harmony OS)开发学习手册
一、入门必看
- 应用开发导读(ArkTS)
- .……
二、HarmonyOS 概念
- 系统定义
- 技术架构
- 技术特性
- 系统安全
- …
三、如何快速入门?《鸿蒙基础入门学习指南》
- 基本概念
- 构建第一个ArkTS应用
- .……
四、开发基础知识
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- .……
五、基于ArkTS 开发
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 7.网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- .……
更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》