《导航切换》案例
通过该案例,我们可以熟练掌握以下知识点
● 使用页Tabs组件进行页面导航
● Swiper组件实现轮播图、
● Grid网格布局
● 以及List列表布局
● 结构化数据封装
● 路由页面切换
1.页面效果
点击登录之后就会进入首页,效果如下图①所示。

2.页面导航
为了开发方便,把图①效果简化为图②,先把页面导航做出来。

完成上述导航效果,实际上由3个页面构成
● MainPage.ets 用于实现页面导航布局
● Home.ets 用于展示首页内容
● Setting.ets 用于展示我的页面内容
2.1MainPage
在pages目录下创建MainPage页面,使用Tabs组件进行页面导航,我们先把页面导航效果做出来。
点击查看代码
import { Home } from '../view/Home'
import { Setting } from '../view/Setting'
@Entry
@Component
struct MainPage {
@State currentIndex: number = 0
@Builder
TabBuilder(title: string, index: number, selectedImg: Resource, normalImg: Resource) {
Column() {
Image(this.currentIndex === index ? selectedImg : normalImg)
.width(25)
.height(25)
Text(title)
.margin({ top: 4 })
.fontSize(10)
.fontColor(this.currentIndex === index ? '#1698CE' : '#6B6B6B')
}
.justifyContent(FlexAlign.Center)
.height(56)
.width('100%')
.onClick(() => {
this.currentIndex = index;
this.tabsController.changeIndex(this.currentIndex);
})
}
private tabsController: TabsController = new TabsController();
build() {
Tabs({
barPosition: BarPosition.End,
controller: this.tabsController
}) {
TabContent() {
Home()
}
.padding({ left: 12, right: 12 })
.backgroundColor('#F1F3FS')
.tabBar(this.TabBuilder('首页', 0,
$r('app.media.home_selected'), $r('app.media.home_normal')))
TabContent() {
Setting()
}
.padding({ left: 12, right: 12 })
.backgroundColor('#F1F3FS')
.tabBar(this.TabBuilder('我的', 1,
$r('app.media.mine_selected'), $r('app.media.mine_normal')))
}
.width('100%')
.backgroundColor(Color.White)
.barHeight(56)
.onChange((index: number) => {
this.currentIndex = index;
})
}
}
点击查看代码
@Component
export struct Setting {
build() {
Column() {
Text('我的')
}.width('100%')
.height('100%').justifyContent(FlexAlign.Center)
}
}

整体采用Colum布局完成,依次从上到下进行代码编写
点击查看代码
@Entry
@Component
export struct Home {
build() {
Column({ space: 12 }) {
//Text头部标题
//Swiper轮播图
//Text文本
//FristGrid网格
//SecondGrid网格
}
}
}
3.1 头部标题
点击查看代码
Text('首页')
.fontSize(24)
.fontWeight(FontWeight.Medium)
.width('100%')
.margin({top:12})
点击查看代码
//导出MainViewModel类,以便其他位置使用
export class MainViewModel {
getSwiperImages(): Array<Resource> {
let swiperImages: Resource[] = [
$r('app.media.fig1'),
$r('app.media.fig2'),
$r('app.media.fig3'),
$r('app.media.fig4'),
]
return swiperImages;
}
getFirstGridData(): Array<FirstGridItemData> {
let firstGridData: FirstGridItemData[] = [
new FirstGridItemData('我的最爱', $r('app.media.love')),
new FirstGridItemData('历史记录', $r('app.media.record')),
new FirstGridItemData('消息', $r('app.media.message')),
new FirstGridItemData('购物车', $r('app.media.shopping')),
new FirstGridItemData('我的目标', $r('app.media.target')),
new FirstGridItemData('圈子', $r('app.media.circle')),
new FirstGridItemData('收藏', $r('app.media.favorite')),
new FirstGridItemData('回收站', $r('app.media.recycle')),
]
return firstGridData;
}
}
//创建对象并导出
export default new MainViewModel();
3.2.2 加载数据到界面
点击查看代码
Swiper() {
ForEach(MainViewModel.getSwiperImages(), (img: Resource) => {
Image(img).borderRadius(16)
.width('100%')
})
}
.margin({ top: 12 })
.autoPlay(true) //自动播放
点击查看代码
//第一个网格的Item数据模型
export class FirstGridItemData {
title: string //item标题
img: Resource //item图标
constructor(title: string, img: Resource) {
this.title = title;
this.img = img;
}
}
点击查看代码
//导出MainViewModel类,以便其他位置使用
export class MainViewModel {
//...
getFirstGridData(): Array<FirstGridItemData> {
let firstGridData: FirstGridItemData[] = [
new FirstGridItemData('我的最爱', $r('app.media.love')),
new FirstGridItemData('历史记录', $r('app.media.record')),
new FirstGridItemData('消息', $r('app.media.message')),
new FirstGridItemData('购物车', $r('app.media.shopping')),
new FirstGridItemData('我的目标', $r('app.media.target')),
new FirstGridItemData('圈子', $r('app.media.circle')),
new FirstGridItemData('收藏', $r('app.media.favorite')),
new FirstGridItemData('回收站', $r('app.media.recycle')),
]
return firstGridData;
}
}
//创建对象并导出
export default new MainViewModel();
点击查看代码
Grid() {
ForEach(MainViewModel.getFirstGridData(), (item: FirstGridItemData) => {
GridItem() {
Column() {
Image(item.img)
.width(24)
.height(24)
Text(item.title)
.fontSize(12)
.margin({ top: 4 })
}
}
})
}
.height(124)
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(18)
.rowsGap(12)
.backgroundColor(Color.White)
.borderRadius(24)
点击查看代码
//第二个网格的Item数据模型
export class SecondGridItemData{
title:string
secondTitle:string
img: Resource
constructor(title: string, secondTitle: string, img: Resource) {
this.title = title;
this.secondTitle = secondTitle;
this.img = img;
}
}
点击查看代码
getSecondGridData():Array<SecondGridItemData>{
let secondGridItemData: SecondGridItemData[] = [
new SecondGridItemData('排行榜','厦门站,我们不见不散',$r('app.media.top')),
new SecondGridItemData('新品发布','厦门站,我们部件不散',$r('app.media.new')),
new SecondGridItemData('打牌闪购','更多大牌',$r('app.media.brand')),
new SecondGridItemData('发现好物','厦门站,我们不见不散',$r('app.media.found')),
]
return secondGridItemData
}
点击查看代码
//...Text(’列表‘)
Grid() {
ForEach(MainViewModel.getSecondGridData(), (item: SecondGridItemData) => {
GridItem() {
Column() {
Text(item.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(item.secondTitle)
.fontSize(12)
.fontColor('#99182431')
.margin({ top: 4 })
}
}
.padding({ top: 8, left: 8 })
.align(Alignment.TopStart)
.backgroundImage(item.img)
.backgroundImageSize(ImageSize.Cover) //背景图、居中填充
.borderRadius(12)
.width('100%')
.height('100%')
})
}
.width('100%')
.height(260)
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.margin({ bottom: 55 })

如上图所示,整体采用Column布局,然后依次从上到下完成代码编写。
4.1 个人信息
点击查看代码
import { ListItemData } from '../viewmodel/ItemData'
import MainViewModel from '../viewmodel/MainViewModel'
import router from '@ohos.router'
@Entry
@Component
export struct Setting {
build() {
Column() {
//1. 头部标题
Text('我的')
.fontSize(24)
.fontWeight(FontWeight.Medium)
.width('100%')
.margin({ top: 12 })
//2. 个人信息
Row() {
Image($r('app.media.account'))
.width(45)
Column() {
Text('李先生').fontSize(18).fontWeight(FontWeight.Bold)
Text('quarkn@forxmail.com')
}.alignItems(HorizontalAlign.Start).margin({ left: 25 })
}
.justifyContent(FlexAlign.Start)
.width('100%')
.height(100)
.backgroundColor(Color.White)
.margin({ top: 20 })
.padding({ left: 20 })
.borderRadius(12)
}.width('100%').height('100%')
}
}
点击查看代码
import { ListItemData } from '../viewmodel/ItemData'
import MainViewModel from '../viewmodel/MainViewModel'
import router from '@ohos.router'
@Entry
@Component
export struct Setting {
build() {
Column() {
//1. 头部标题...
//2. 头部标题...
//3. 列表
List() {
ForEach(MainViewModel.getListData(), (item: ListItemData) => {
ListItem() {
Row() {
Image(item.img).width(25)
Text(item.title).margin({ left: 10 })
Blank()
if(item.index===0){
Toggle({ type: ToggleType.Switch, isOn: false })
}else {
Image($r('app.media.arrow')).width(20)
}
}
.width('100%')
.height(50)
.backgroundColor(Color.White)
.padding({ left: 10, right: 10 })
}
})
}.borderRadius(12).margin({top:15}).divider({
strokeWidth:0.25,
color:Color.Grey,
startMargin:40,
endMargin: 10
})
Blank()
Button('退出登录').width('80%').backgroundColor('#dedede')
.margin({bottom:100}).fontColor(Color.Red)
.onClick(()=>{
router.replaceUrl({ url: "pages/LoginPage" })
})
}.width('100%').height('100%')
}
}
点击查看代码
import { ListItemData } from '../viewmodel/ItemData'
import MainViewModel from '../viewmodel/MainViewModel'
import router from '@ohos.router'
@Entry
@Component
export struct Setting {
build() {
Column() {
//1. 头部标题...
//2. 头部标题...
//3. 列表...
Blank() //弹性空白
Button('退出登录').width('80%').backgroundColor('#dedede')
.margin({bottom:100}).fontColor(Color.Red)
.onClick(()=>{
router.replaceUrl({ url: "pages/LoginPage" }) //跳转到登录页
})
}.width('100%').height('100%')
}
}


浙公网安备 33010602011771号