《導航切換》案例
通過該案例,我們可以熟練掌握以下知識點
● 使用頁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號