本节主要介绍“登录”页面的实现,页面使用Column容器组件布局,由Image、Text、TextInput、Button、LoadingProgress等基础组件构成。
// LoginPage.ets
@Entry
@Component
struct LoginPage {
...
build() {
Column() {
Image($r('app.media.logo'))
...
Text($r('app.string.login_page'))
...
Text($r('app.string.login_more'))
...
TextInput({ placeholder: $r('app.string.account') })
...
TextInput({ placeholder: $r('app.string.password') })
...
Button($r('app.string.login'), { type: ButtonType.Capsule })
...
if (this.isShowProgress) {
LoadingProgress()
...
}
...
}
...
}
}
当用户登录前,需要获取用户输入的帐号和密码才能执行登录逻辑。给TextInput设置onChange事件,在onChange事件里面实时获取用户输入的文本信息。
// LoginPage.ets
TextInput({ placeholder: $r('app.string.account') })
.maxLength(CommonConstants.INPUT_ACCOUNT_LENGTH)
.type(InputType.Number)
.inputStyle()
.onChange((value: string) => {
this.account = value;
})
给登录按钮绑定onClick事件,调用login方法模拟登录。定义变量isShowProgress结合条件渲染if用来控制LoadingProgress的显示和隐藏。当用户点击按钮时设置isShowProgress为true,即显示LoadingProgress;使用定时器setTimeout设置isShowProgress 2秒后为false,即隐藏LoadingProgress,然后执行跳转到首页的逻辑。
// LoginPage.ets
@Entry
@Component
struct LoginPage {
...
@State isShowProgress: boolean = false;
private timeOutId: number = -1;
...
login(): void {
...
this.isShowProgress = true;
if (this.timeOutId === -1) {
this.timeOutId = setTimeout(() => {
this.isShowProgress = false;
this.timeOutId = -1;
router.replaceUrl({ url: 'pages/MainPage' });
}, CommonConstants.LOGIN_DELAY_TIME);
}
}
...
build() {
Column() {
...
Button($r('app.string.login'), { type: ButtonType.Capsule })
...
.onClick(() => {
this.login();
})
...
if (this.isShowProgress) {
LoadingProgress()
...
}
...
}
...
}
}
页面间的跳转可以使用router模块相关API来实现,使用前需要先导入该模块,然后使用router.replaceUrl()方法实现页面跳转。
// LoginPage.ets
import router from '@ohos.router';
login(): void {
...
this.timeOutId = setTimeout(() => {
this.isShowProgress = false;
this.timeOutId = -1;
router.replaceUrl({ url: 'pages/MainPage' });
}, CommonConstants.LOGIN_DELAY_TIME);
}
由于“首页”和“我的”页面中有多处图片和文字的组合,因此提取出ItemData类。在MainViewModel.ets文件中对页面使用的资源进行定义,在MainViewModel.ets文件中定义数据。
// ItemData.ets
export default class PageResource {
title: Resource;
img: Resource;
others?: Resource;
constructor(title: Resource, img: Resource, others?: Resource) {
this.title = title;
this.img = img;
this.others = others;
}
}
// MainViewModel.ets
import ItemData from './ItemData';
export class MainViewModel {
...
getFirstGridData(): Array<ItemData> {
let firstGridData: ItemData[] = [
new ItemData($r('app.string.my_love'), $r('app.media.love')),
new ItemData($r('app.string.history_record'), $r('app.media.record')),
...
];
return firstGridData;
}
...
}
export default new MainViewModel();
从前面介绍章节的示意图可以看出,本示例由两个tab页组成,使用Tabs组件来实现,提取tabBar的公共样式,同时设置TabContent和Tabs的backgroundColor来实现底部tabBar栏背景色突出的效果。
// MainPage.ets
Tabs({
barPosition: BarPosition.End,
controller: this.tabsController
}) {
TabContent() {
...
}
...
.backgroundColor($r('app.color.mainPage_backgroundColor')) // “首页”的页面背景色
.tabBar(this.TabBuilder(CommonConstants.HOME_TITLE, CommonConstants.HOME_TAB_INDEX,
$r('app.media.home_selected'), $r('app.media.home_normal')))
...
}
.width(CommonConstants.FULL_PARENT)
.backgroundColor(Color.White) // 底部tabBar栏背景色
...
.onChange((index: number) => {
this.currentIndex = index;
})
...
从效果图可以看出“首页”由三部分内容组成分别是轮播图、24栅格图、44栅格图。首先使用Swiper组件实现轮播图,无需设置图片大小。
// Home.ets
Swiper(this.swiperController) {
ForEach(mainViewModel.getSwiperImages(), (img: Resource) => {
Image(img).borderRadius($r('app.float.home_swiper_borderRadius'))
}, (img: Resource) => JSON.stringify(img.id))
}
.margin({ top: $r('app.float.home_swiper_margin') })
.autoPlay(true)
然后使用Grid组件实现2*4栅格图。
// Home.ets
Grid() {
ForEach(mainViewModel.getFirstGridData(), (item: ItemData) => {
GridItem() {
Column() {
Image(item.img)
.width($r('app.float.home_homeCell_size'))
.height($r('app.float.home_homeCell_size'))
Text(item.title)
.fontSize($r('app.float.little_text_size'))
.margin({ top: $r('app.float.home_homeCell_margin') })
}
}
}, (item: ItemData) => JSON.stringify(item))
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
...
使用Grid组件实现4*4栅格列表栏,其中单个栅格中有一张背景图片和两行字体不同的文本,因此在Column组件中放置两个Text组件,并设置背景图,注意Grid组件必须设置高度,否则可能出现页面空白。
// Home.ets
Grid() {
ForEach(mainViewModel.getSecondGridData(), (secondItem: ItemData) => {
GridItem() {
Column() {
Text(secondItem.title)
...
Text(secondItem.others)
...
}
.alignItems(HorizontalAlign.Start)
}
...
.backgroundImage(secondItem.img)
.backgroundImageSize(ImageSize.Cover)
...
}, (secondItem: ItemData) => JSON.stringify(secondItem))
}
...
.height($r('app.float.home_secondGrid_height'))
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
...
使用List组件结合ForEach语句来实现页面列表内容,其中引用了settingCell子组件,列表间的灰色分割线可以使用Divider属性实现。
// Setting.ets
List() {
ForEach(mainViewModel.getSettingListData(), (item: ItemData) => {
ListItem() {
this.settingCell(item)
}
.height($r('app.float.setting_list_height'))
}, (item:ItemData) => JSON.stringify(item))
}
.backgroundColor(Color.White)
.divider({
...
})
...
@Builder settingCell(item: ItemData) {
Row() {
Row({ space: CommonConstants.COMMON_SPACE }) {
Image(item.img)
...
Text(item.title)
...
}
if (item.others === null) {
Image($r('app.media.right_grey'))
...
} else {
Toggle({ type: ToggleType.Switch, isOn: false })
}
}
.justifyContent(FlexAlign.SpaceBetween)
...
}
HarmonyOS ArkUI提供了丰富多样的UI组件,您可以使用这些组件轻松地编写出更加丰富、漂亮的界面。更多鸿蒙的基础技术学习,可以前往主页联系拿文档。下面分享一份鸿蒙学习技能路线图:完整高清版找我保存
通过一个简单的购物社交应用示例,学习如何使用常用的基础组件和容器组件。本示例主要包含:“登录”、“首页”、“我的”三个页面。下面是效果图: