每一个App都应该有一个首页,在Android中一般由MainActivity + Navigation + Fragment * N (随便你怎么组合,用别的也一样),鸿蒙呢?瞅瞅吧。阿弥陀佛,苦逼Android学完Java学Dart、学完Dart学Kotlin、学完Kotlin学Compose、学完Compose,HarmonyOS来啦!艹(更别说还有Framework
)艹艹艹。
如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信或邮件中提出,非常感谢您的支持。🙏
因为众所不周知的原因,用的是编译SDK是9。DEV版本是DevEco Studio 4.0 Release。以及我只简单的写了一下底部的Tab,具体的内容也只有一个Text作为填充物~~~ 主要还是分享给大家如何写一个首页的基本代码啦~。
我们使用最最最基本的项目结构就好了,你可能需要如此做
File->New->Create Project->Application->Empty Ability->Next->(API 9)->Done->Finish 完事。
显然,一个首页会有一个底部导航栏。一般而言会是“文字+图片”的组合,并且都具有选中状态、非选中状态。再显然这玩意是个数组。我们准备下
新建一个data/MainCategory.ets
文件
记得新建一个data
文件夹
简单的在里面定义一个数据结构
// 定义一个接口来表示项目类别的结构。
export interface ItemCategory {
// 当类别被选中时显示的图像资源。
// 图像文件的引用
selectedImage: Resource,
// 未被选中时显示的图像资源。
// 用于在用户界面上区分选中和未选中的状态。
unselectedImage: Resource,
// 类别的标题资源。
// 一个字符串资源的引用
title: Resource
}
贴心的加上注释。PS:export
表示某个实体(比如一个类、接口、变量或函数)应该被导出,使得它可以在其他文件或模块中被导入和使用。
构造一丢丢数据
我们打算做四个页面,所以准备四个数据吧~
export const MAIN_CATEGORIES: ItemCategory[] =
[
{
selectedImage: $r('app.media.icon_home_select'),
unselectedImage: $r('app.media.icon_home_unselect'),
title: $r("app.string.main_home")
},
{
selectedImage: $r('app.media.icon_group_select'),
unselectedImage: $r('app.media.icon_group_unselect'),
title: $r("app.string.main_group")
},
{
selectedImage: $r('app.media.icon_message_select'),
unselectedImage: $r('app.media.icon_message_unselect'),
title: $r("app.string.main_message")
},
{
selectedImage: $r('app.media.icon_mine_select'),
unselectedImage: $r('app.media.icon_mine_unselect'),
title: $r("app.string.main_mine")
}
]
PS:const
关键字用于声明一个常量,意味着一旦被赋值后,其值就不能被改变(PPS:如果变量引用的是一个对象或数组,那么对象的属性或数组的元素是可以被修改)。
回到我们的Index.ets
。让我们导入刚刚准备的数据~
import { ItemCategory, MAIN_CATEGORIES } from './data/MainCategory'
import
就是导入的意思,这玩意一般在文件的最前面。
{}
用来声明你要导入这个文件中的什么(PS:这玩意能换名字)
import { ItemCategory, MAIN_CATEGORIES as NewName} from './data/MainCategory'
from
显然没什么用
./
聪明的你,很清楚的知道这玩意的意思是:表示当前文件所在目录。顺带还想到了../
表示:父目录。那还有......../
?抱歉,没有了。但是你可以这么写
import { ItemCategory, MAIN_CATEGORIES as NewName} from '../../main/ets/data/MainCategory'
这样你就可以无限套娃了~一直../
下去吧!少年!
首先,肯定有当前展示页面之分,所以我们需要记录下选中的页面的Tab的Index
@State tabCurrentIndex: number = 0
PS:@State
装饰的状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。当状态改变时,UI会发生对应的渲染改变(官网抄的)。
我们直接使用鸿蒙之超能Tab之Tab,
import { ItemCategory, MAIN_CATEGORIES } from './data/MainCategory'
/*生成的别管*/
@Entry
/*生成的别管*/
@Component
/*struct 生成的别管*/
struct Index {
@State tabCurrentIndex: number = 0
/*build UI都写在这*/
build() {
// 创建 Tabs 组件,设置其属性
Tabs({ barPosition: BarPosition.End }) {
// ForEach 用于遍历 MAIN_CATEGORIES,为每个元素创建 TabContent 组件
ForEach(MAIN_CATEGORIES, (item: ItemCategory, index: number) => {
// 创建 TabContent 组件
TabContent() {
// 在这里可以添加 TabContent 组件的内容
}
// 设置 TabContent 组件的 tabBar 属性
.tabBar(/* 这里可以设置 tabBar 相关属性 */)
})
}
// 设置 Tabs 组件的其他属性
.scrollable(false) // 设置是否可滚动 (首页一般来说,左右不能滑动吧?)
.barHeight(56) // 设置选项卡高度
.barWidth('100%') // 设置选项卡宽度
.vertical(false) // 设置选项卡排列方式(垂直或水平)
.backgroundColor(0xFFFEFEFE) // 设置背景色
// 设置当选项卡改变时的回调函数
.onChange((index: number) => {
this.tabCurrentIndex = index; // 更新当前选中的选项卡索引
})
}
}
可以看到,我们的Tab
已经准备好了!然后我们需要填充下TabBar
。
// 使用 @Builder 装饰器,表示 TabBarBuilder 是一个构建器方法
@Builder
TabBarBuilder(index: number, selectedImage: Resource, unselectedImage: Resource, tabBarName: Resource) {
// 构建一个列布局(Column),用于垂直排列子组件
Column() {
// 在列中添加一个图像组件
// 如果当前索引与传入的索引相同,则显示选中的图像,否则显示未选中的图像
Image(this.tabCurrentIndex === index ? selectedImage : unselectedImage)
.width(24) // 设置图像宽度
.height(24) // 设置图像高度
.margin({ bottom: 4 }) // 设置底部外边距
?
// 在列中添加一个文本组件,用于显示选项卡名称
Text(tabBarName)
.fontSize(10) // 设置字体大小
.fontFamily('HarmonyHeiTi-Medium') // 设置字体
.fontColor(this.tabCurrentIndex === index ? 0xFF2E2F2E : 0xFF848683) // 设置字体颜色,根据选中状态改变
}
// 设置列组件的宽度为 100%
.width('100%')
// 设置列组件的内边距
.padding({ top: 6, bottom: 6 })
// 设置子项在水平方向上的对齐方式为居中
.alignItems(HorizontalAlign.Center)
// 设置组件的 ID,使用索引来确保唯一性
.id(`tabBar${index}`)
}
那么往Tab
组件里面一塞
tabBar(this.TabBarBuilder(index, item.selectedImage, item.unselectedImage, item.title))
那么Tab就完成啦~~~
重要的页面来了。
为了不让Index内太臃肿,我们直接!新建一个 MainPageContainer类,并塞入一个Text
@Component
export struct MainPageContainer {
private mTitle: Resource;
build() {
Column() {
Text(this.mTitle) // 使用 mTitle 作为文本内容
.fontSize(50)
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
.fontColor(0xFF9FE748)
}
.height('100%')
.padding({ top: 12 })
}
}
然后我们直接在Index中导入一下
import { MainPageContainer } from './MainPageContainer'
再这么一用
TabContent() {
MainPageContainer({ mTitle: item.title })
}
完事~
最后效果放在最前面啦~
这玩意挺简单了,但是这DevEco-Studio是我用过的最垃圾的工具了。真的烂。这代码提醒,这代码补全,不如不要,啥也提醒不了,就只会“Did you mean xxxx”、“ignore x x x x"。💩。
为了能让大家更好的学习鸿蒙 (Harmony OS) 开发技术,这边特意整理了《鸿蒙 (Harmony OS)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
HarmonyOS 概念:https://qr21.cn/FV7h05
如何快速入门:https://qr21.cn/FV7h05
开发基础知识:https://qr21.cn/FV7h05
基于ArkTS 开发:https://qr21.cn/FV7h05