本示例主要包含:“登录”、“首页”、“我的”三个页面。

完整示例

HarmonyOS-UI: HarmonyOS一些UI示例 - Gitee.com

软件要求

DevEco Studio版本:DevEco Studio 3.1 Release。HarmonyOS SDK版本:API version 9。

代码结构

├──entry/src/main/ets // 代码区│ ├──common│ │ └──constants│ │      └──CommonConstants.ets // 公共常量类│ ├──entryability│ │ └──EntryAbility.ts // 程序入口类│ ├──pages│ │ ├──Login.ets // 登录界面│ │ └──MainPage.ets // 主界面│ ├──view│ │ ├──Home.ets // 首页│ │ └──Mime.ets // 我的│ └──viewmodel│ ├──ItemData.ets // 列表数据实体类│ └──MainViewModel.ets // 主界面视图Model└──entry/src/main/resources // 应用资源目录

实现“登录”页面

页面使用Column容器组件布局,由Image、Text、TextInput、Button、LoadingProgress等基础组件构成。

代码整体结构

@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事件里面实时获取用户输入的文本信息。

控制LoadingProgress显示和隐藏

给登录按钮绑定onClick事件,调用login方法模拟登录。定义变量isShowProgress结合条件渲染if用来控制LoadingProgress的显示和隐藏。当用户点击按钮时设置isShowProgress为true,即显示LoadingProgress;使用定时器setTimeout设置isShowProgress 2秒后为false,即隐藏LoadingProgress,然后执行跳转到首页的逻辑。

实现页面跳转

页面间的跳转可以使用router模块相关API来实现,使用前需要先导入该模块,然后使用router.replaceUrl()方法实现页面跳转。

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);

}

}

Login完整代码

import prompt from '@system.prompt';

import router from '@ohos.router';

import CommonConstants from '../common/constants/CommonConstants'

@Entry

@Component

struct Login {

@State account: string = '';

@State password: string = '';

@State isShowProgress: boolean = false

private timeOutId: number = -1

@Builder

imageButton(src: Resource) {

Button({ type: ButtonType.Circle, stateEffect: true }) {

Image(src)

}

.height($r('app.float.other_login_image_size'))

.width($r('app.float.other_login_image_size'))

.backgroundColor($r('app.color.background'))

.margin({bottom:$r('app.float.other_login_margin_bottom')})

}

login(): void {

if (this.account === '' || this.password === '') {

prompt.showToast({

message: CommonConstants.INPUT_NOT_EMPTY

})

} else {

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() {

Image($r('app.media.logo'))

.width($r('app.float.logo_image_size'))

.height($r('app.float.logo_image_size'))

.margin({ top: $r('app.float.logo_margin_top'), bottom: $r('app.float.logo_margin_bottom') })

Text($r('app.string.login_module_desc_no'))

.fontSize($r('app.float.page_title_text_size'))

.fontWeight(FontWeight.Medium)

.fontColor($r('app.color.login_text_color'))

Text($r('app.string.login_module_desc_de'))

.fontSize($r('app.float.normal_text_size'))

.fontWeight(FontWeight.Medium)

.fontColor($r('app.color.login_more_text_color'))

.margin({ bottom: $r('app.float.login_more_margin_bottom'), top: $r('app.float.login_more_margin_top') })

TextInput({ placeholder: $r('app.string.account') })

.maxLength(CommonConstants.INPUT_ACCOUNT_LENGTH)

.inputStyle()

.onChange((value: string) => {

this.account = value

})

Line().lineStyle()

TextInput({ placeholder: $r('app.string.password') })

.maxLength(CommonConstants.INPUT_PASSWORD_LENGTH)

.inputStyle()

.type(InputType.Password)

.onChange((value: string) => {

this.password = value

})

Line().lineStyle()

Row({ space: CommonConstants.COMMON_SPACE_20 }) {

Text($r('app.string.message_login')).blueTextStyle()

Text($r('app.string.forgot_password')).blueTextStyle()

}

.justifyContent(FlexAlign.SpaceBetween)

.width(CommonConstants.PAGE_WIDTH)

Button($r('app.string.login'), { type: ButtonType.Capsule })

.width(CommonConstants.BUTTON_WIDTH)

.height($r('app.float.login_button_height'))

.fontSize($r('app.float.normal_text_size'))

.fontWeight(FontWeight.Medium)

.backgroundColor($r('app.color.login_button_color'))

.margin({ top: $r('app.float.login_button_margin_top'), bottom: $r('app.float.login_button_margin_bottom') })

.onClick(() => {

this.login()

})

Text($r('app.string.register_account'))

.fontColor($r('app.color.login_blue_text_color'))

.fontSize($r('app.float.normal_text_size'))

.fontWeight(FontWeight.Medium)

if (this.isShowProgress) {

LoadingProgress()

.color($r('app.color.loading_color'))

.width($r('app.float.login_progress_size'))

.height($r('app.float.login_progress_size'))

.margin({ top: $r('app.float.login_progress_margin_top') })

}

Blank()

Text($r('app.string.other_login_method'))

.fontColor($r('app.color.other_login_text_color'))

.fontSize($r('app.float.little_text_size'))

.fontWeight(FontWeight.Medium)

.margin({ top: $r('app.float.other_login_margin_top'), bottom: $r('app.float.other_login_margin_bottom') })

Row({ space: CommonConstants.LOGIN_METHODS_SPACE }) {

this.imageButton($r('app.media.login_method1'))

this.imageButton($r('app.media.login_method2'))

this.imageButton($r('app.media.login_method3'))

}

}

.backgroundColor($r('app.color.background'))

.height(CommonConstants.FULL_PARENT)

.width(CommonConstants.FULL_PARENT)

.padding({

left: $r('app.float.page_padding_hor'),

right: $r('app.float.page_padding_hor'),

bottom: $r('app.float.login_page_padding_bottom')

})

}

}

@Extend(TextInput) function inputStyle() {

.placeholderColor($r('app.color.placeholder_color'))

.height($r('app.float.login_input_height'))

.fontSize($r('app.float.big_text_size'))

.backgroundColor($r('app.color.background'))

.width(CommonConstants.FULL_PARENT)

.margin({ top: $r('app.float.input_margin_top') })

}

@Extend(Text) function blueTextStyle() {

.fontColor($r('app.color.login_blue_text_color'))

.fontSize($r('app.float.small_text_size'))

.fontWeight(FontWeight.Medium)

.margin({ top: $r('app.float.forgot_margin_top') })

}

@Extend(Line) function lineStyle() {

.width(CommonConstants.FULL_PARENT)

.height($r('app.float.line_height'))

.backgroundColor($r('app.color.line_color'))

}

实现“首页”和“我的”页面

本示例由两个tab页组成,使用Tabs组件来实现,提取tabBar的公共样式,同时设置TabContent和Tabs的backgroundColor来实现底部tabBar栏背景色突出的效果。

定义资源数据

由于“首页”和“我的”页面中有多处图片和文字的组合,因此提取出ItemData类。在MainViewModel.ets文件中对页面使用的资源进行定义。

MainViewModel代码

import { ItemData } from './ItemData';

export class MainViewModel {

private swiperImages: Resource[] = [

$r('app.media.fig1'),

$r('app.media.fig2'),

$r('app.media.fig3'),

$r('app.media.fig4')

];

private firstGridData: ItemData[] = [

new ItemData($r('app.string.my_love'), $r('app.media.love')),

new ItemData($r('app.string.history_record'), $r('app.media.record')),

new ItemData($r('app.string.message'), $r('app.media.message')),

new ItemData($r('app.string.shopping_cart'), $r('app.media.shopping')),

new ItemData($r('app.string.my_goal'), $r('app.media.target')),

new ItemData($r('app.string.group'), $r('app.media.circle')),

new ItemData($r('app.string.favorites'), $r('app.media.favorite')),

new ItemData($r('app.string.recycle_bin'), $r('app.media.recycle'))

];

private secondGridData: ItemData[] = [

new ItemData($r('app.string.mainPage_top'), $r('app.media.top'), $r('app.string.mainPage_text_top')),

new ItemData($r('app.string.mainPage_new'), $r('app.media.new'), $r('app.string.mainPage_text_new')),

new ItemData($r('app.string.mainPage_brand'), $r('app.media.brand'), $r('app.string.mainPage_text_brand')),

new ItemData($r('app.string.mainPage_found'), $r('app.media.found'), $r('app.string.mainPage_text_found')),

];

private settingListData: ItemData[] = [

new ItemData($r('app.string.setting_list_news'), $r('app.media.news'), $r("app.string.setting_toggle")),

new ItemData($r('app.string.setting_list_data'), $r('app.media.data')),

new ItemData($r('app.string.setting_list_menu'), $r('app.media.menu')),

new ItemData($r('app.string.setting_list_about'), $r('app.media.about')),

new ItemData($r('app.string.setting_list_storage'), $r('app.media.storage')),

new ItemData($r('app.string.setting_list_privacy'), $r('app.media.privacy'))

];

getSwiperImags(): Array {

return this.swiperImages

}

getGridData(type: number): Array {

switch (type) {

case 0:

return this.firstGridData

break

case 1:

return this.secondGridData

break

default:

return this.firstGridData

break

}

}

getSettingListData(): Array{

return this.settingListData

}

}

export default new MainViewModel()

ItemData代码

export class ItemData{

/**

* Text of list item.

*/

title: Resource;

/**

* Image of list item.

*/

img: Resource;

/**

* Other resource of list item.

*/

others?: Resource;

constructor(title: Resource, img: Resource, others?: Resource) {

this.title = title;

this.img = img;

this.others = others;

}

}

实现“首页”内容

从效果图可以看出“首页”由三部分内容组成分别是轮播图、2*4栅格图、2*2栅格图。首先使用Swiper组件实现轮播图,无需设置图片大小。

然后使用Grid组件实现2*4栅格图。

使用Grid组件实现2*2栅格列表栏,其中单个栅格中有一张背景图片和两行字体不同的文本,因此在Column组件中放置两个Text组件,并设置背景图,注意Grid组件必须设置高度,否则可能出现页面空白。

MainPage代码

import router from '@ohos.router'

import CommonConstants from '../common/constants/CommonConstants'

import Home from '../view/Home'

import Mime from '../view/Mime'

@Entry

@Component

struct MainPage {

@State fontColor: string = '#182431'

@State selectedFontColor: string = '#007DFF'

@State currentIndex: number = 0

private controller: TabsController = new TabsController()

@Builder TabBuilder(title: string, index: number, selectedImg: Resource, normalImg: Resource) {

Column() {

Image(this.currentIndex === index ? selectedImg : normalImg)

.width($r('app.float.mainPage_baseTab_size'))

.height($r('app.float.mainPage_baseTab_size'))

.objectFit(ImageFit.Contain)

Text(title)

.fontColor(this.currentIndex === index ? $r('app.color.mainPage_selected') : $r('app.color.mainPage_normal'))

.fontSize($r('app.float.main_tab_fontSize'))

}

.width('100%')

}

build() {

Column() {

Tabs({ barPosition: BarPosition.End, controller: this.controller }) {

TabContent() {

Home()

}.tabBar(this.TabBuilder(

CommonConstants.HOME_TITLE,

CommonConstants.HOME_TAB_INDEX,

$r('app.media.home_selected'),

$r('app.media.home_normal')))

TabContent() {

Mime()

}.tabBar(this.TabBuilder(

CommonConstants.MINE_TITLE,

CommonConstants.MINE_TAB_INDEX,

$r('app.media.mine_selected'),

$r('app.media.mine_normal')))

}

.vertical(false)

.width(CommonConstants.FULL_PARENT)

.backgroundColor(Color.White)

.barHeight($r('app.float.mainPage_barHeight'))

.barMode(BarMode.Fixed)

.onChange((index: number) => {

this.currentIndex = index

/* if(this.currentIndex == 1){

router.pushUrl({

url:'./pages/Mime'

})

}*/

})

}

.width(CommonConstants.FULL_PARENT)

.height(CommonConstants.FULL_PARENT)

.justifyContent(FlexAlign.End)

}

}

Home代码

import CommonConstants from '../common/constants/CommonConstants'

import { ItemData } from '../viewmodel/ItemData'

import MainViewModel from '../viewmodel/MainViewModel'

@Component

export default struct Home {

private swiperController: SwiperController = new SwiperController()

private gridScroller: Scroller = new Scroller()

build() {

Column({ space: CommonConstants.COMMON_SPACE }) {

Column() {

Text($r('app.string.mainPage_tabTitles_home'))

.fontWeight(FontWeight.Medium)

.fontSize($r('app.float.page_title_text_size'))

.margin({ top: $r('app.float.mainPage_tabTitles_margin') })

.padding({ left: $r('app.float.mainPage_tabTitles_padding') })

}

.width(CommonConstants.FULL_PARENT)

.alignItems(HorizontalAlign.Start)

Swiper(this.swiperController) {

ForEach(MainViewModel.getSwiperImags(), (img: Resource) => {

Image(img).borderRadius($r('app.float.home_swiper_borderRadius'))

}, (img: Resource) => JSON.stringify(img.id))

}

.width(CommonConstants.FULL_PARENT)

.height($r('app.float.home_swiper_height'))

.margin({ top: $r('app.float.home_swiper_margin') })

.autoPlay(true)

Grid() {

ForEach(MainViewModel.getGridData(0), (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')

.columnsGap($r('app.float.home_grid_columnsGap'))

.rowsGap($r('app.float.home_grid_rowGap'))

.padding({ top: $r('app.float.home_grid_padding'), bottom: $r('app.float.home_grid_padding') })

.height($r('app.float.home_grid_height'))

.backgroundColor(Color.White)

.borderRadius($r('app.float.home_grid_borderRadius'))

Text($r('app.string.home_list'))

.fontSize($r('app.float.normal_text_size'))

.fontWeight(FontWeight.Medium)

.width(CommonConstants.COMMON_WIDTH_90)

.margin({ top: $r('app.float.home_text_margin') })

Grid(this.gridScroller) {

ForEach(MainViewModel.getGridData(1), (secondItem: ItemData) => {

GridItem() {

Column() {

Text(secondItem.title)

.fontSize($r('app.float.normal_text_size'))

.fontWeight(FontWeight.Medium)

Text(secondItem.others)

.margin({ top: $r('app.float.home_list_margin') })

.fontSize($r('app.float.little_text_size'))

.fontColor($r('app.color.home_grid_fontColor'))

}

.alignItems(HorizontalAlign.Start)

}

.padding({ top: $r('app.float.home_list_padding'), left: $r('app.float.home_list_padding') })

.borderRadius($r('app.float.home_backgroundImage_borderRadius'))

.align(Alignment.TopStart)

.backgroundImage(secondItem.img)

.backgroundImageSize(ImageSize.Cover)

.width(CommonConstants.FULL_PARENT)

.height(CommonConstants.FULL_PARENT)

}, (secondItem: ItemData) => JSON.stringify(secondItem))

}

.width(CommonConstants.COMMON_WIDTH_90)

.height($r('app.float.home_secondGrid_height'))

.columnsTemplate('1fr 1fr')

// .rowsTemplate('1fr 1fr')

.columnsGap($r('app.float.home_grid_columnsGap'))

.rowsGap($r('app.float.home_grid_rowGap'))

.layoutWeight(1)

.onScrollIndex((first: number) => {

console.info('111111111',first.toString())

})

}

.height(CommonConstants.FULL_PARENT)

}

}

实现“我的”页面内容

使用List组件结合ForEach语句来实现页面列表内容。

Mime代码

import CommonConstants from '../common/constants/CommonConstants'

import { ItemData } from '../viewmodel/ItemData'

import MainViewModel from '../viewmodel/MainViewModel'

@Component

export default struct Mime {

@Builder settingCell(item: ItemData) {

Column() {

Row() {

Row({ space: CommonConstants.COMMON_SPACE_10 }) {

Image(item.img)

.width($r('app.float.setting_size'))

.height($r('app.float.setting_size'))

Text(item.title)

.fontSize($r('app.float.normal_text_size'))

}

if (item.others === null || item.others === undefined) {

Image($r('app.media.right_grey'))

.width($r('app.float.setting_jump_width'))

.height($r('app.float.setting_jump_height'))

} else {

Toggle({ type: ToggleType.Switch, isOn: false })

}

}

.justifyContent(FlexAlign.SpaceBetween)

.width(CommonConstants.FULL_PARENT)

}

}

build() {

Column({ space: CommonConstants.COMMON_SPACE_10 }) {

Text('我的')

.width(CommonConstants.COMMON_WIDTH_90)

.height(50)

.fontSize(24)

.fontWeight(600)

Row() {

Image($r('app.media.account'))

.width(50)

.height(50)

Column() {

Text($r('app.string.setting_account_name'))

.fontSize($r('app.float.setting_account_fontSize'))

.fontWeight(400)

Text($r('app.string.setting_account_email'))

.fontSize($r('app.float.little_text_size'))

.margin({ top: $r('app.float.setting_name_margin') })

}

.alignItems(HorizontalAlign.Start)

.margin({ left: $r('app.float.setting_padding') })

}

.margin({ top: $r('app.float.login_progress_margin_top') })

.width(CommonConstants.COMMON_WIDTH_80)

.justifyContent(FlexAlign.Start)

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)

.width(CommonConstants.COMMON_WIDTH_90)

.height(CommonConstants.COMMON_WIDTH_50)

.margin({ top: $r('app.float.other_login_margin_top') })

.borderRadius($r('app.float.setting_list_borderRadius'))

.padding({ top: $r('app.float.setting_list_padding'), bottom: $r('app.float.setting_list_padding') })

Blank()

Button($r('app.string.setting_button'), { type: ButtonType.Capsule })

.width(CommonConstants.BUTTON_WIDTH)

.height($r('app.float.login_button_height'))

.fontSize($r('app.float.normal_text_size'))

.fontColor($r('app.color.setting_button_fontColor'))

.fontWeight(FontWeight.Medium)

.backgroundColor($r('app.color.setting_button_backgroundColor'))

.margin({ bottom: $r('app.float.setting_button_bottom') })

}

.width(CommonConstants.FULL_PARENT)

.height(CommonConstants.FULL_PARENT)

}

}

总结

知识点:

Button、Image、TextInput、Text等基础组件的使用。Column、Row、Grid、List、Tabs等容器组件的使用。

推荐文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: