應(yīng)用:底部導(dǎo)航 — 構(gòu)建 Tab 導(dǎo)航欄的標(biāo)準(zhǔn)模式)
一、應(yīng)用概述底部導(dǎo)航Bottom Navigation是一個(gè)模擬主流 App 底部 Tab 切換的演示應(yīng)用。四個(gè)標(biāo)簽頁首頁、發(fā)現(xiàn)、消息、我的各自關(guān)聯(lián)不同的頁面內(nèi)容點(diǎn)擊標(biāo)簽平滑切換內(nèi)容區(qū)域。底部導(dǎo)航欄是移動(dòng)應(yīng)用中最常見的導(dǎo)航模式iOS 的 UITabBar 和 Android 的 BottomNavigationView 都采用類似設(shè)計(jì)。在 HarmonyOS 中底部導(dǎo)航的實(shí)現(xiàn)沒有使用專門的 TabBar 組件雖然有Tabs組件而是通過RowForEach手動(dòng)構(gòu)建導(dǎo)航欄配合State狀態(tài)驅(qū)動(dòng)內(nèi)容切換。這種「造輪子」的方式反而讓我們更深入地理解了狀態(tài)驅(qū)動(dòng)的本質(zhì)。二、技術(shù)架構(gòu)2.1 應(yīng)用結(jié)構(gòu)┌─────────────────────────────────────┐ │ ? 返回 底部導(dǎo)航 │ ├─────────────────────────────────────┤ │ │ │ 大圖標(biāo) │ │ │ │ 歡迎來到底部導(dǎo)航演示 │ │ 這是首頁的內(nèi)容區(qū)域 │ │ 可以放置各種信息和功能卡片 │ │ │ │ │ ├─────────────────────────────────────┤ │ │ ← 底部導(dǎo)航欄 │ 首頁 發(fā)現(xiàn) 消息 我的 │ └─────────────────────────────────────┘2.2 數(shù)據(jù)模型interface TabItem { title: string; // 標(biāo)簽名稱 icon: string; // emoji 圖標(biāo) content: string; // 頁面內(nèi)容含換行符 color: string; // 標(biāo)簽主題色選中時(shí)使用 }2.3 狀態(tài)變量變量類型用途currentTabnumber當(dāng)前選中的標(biāo)簽索引0-3tabsTabItem[]4 個(gè)標(biāo)簽的配置數(shù)據(jù)三、核心代碼深度解析3.1 狀態(tài)驅(qū)動(dòng)的 Tab 切換State currentTab: number 0;僅用一個(gè)number類型的State變量就驅(qū)動(dòng)了整個(gè)頁面的切換。這個(gè)數(shù)字既是底部導(dǎo)航欄的選中索引也是內(nèi)容區(qū)域的顯示索引。內(nèi)容區(qū)域Column() { Text(this.tabs[this.currentTab].icon).fontSize(64).margin({ bottom: 16 }) Text(this.tabs[this.currentTab].content) .fontSize(16).fontColor(#555).lineHeight(28).textAlign(TextAlign.Center) } .layoutWeight(1).justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center)通過this.currentTab索引tabs數(shù)組動(dòng)態(tài)獲取當(dāng)前標(biāo)簽的 icon、content 和 color。這是 ArkUI 中「數(shù)據(jù)驅(qū)動(dòng) UI」最直接的體現(xiàn)——只需更新currentTab所有相關(guān) UI 自動(dòng)刷新。3.2 底部導(dǎo)航欄Row() { ForEach(this.tabs, (tab: TabItem, idx: number) { Column() { Text(tab.icon).fontSize(22) .opacity(this.currentTab idx ? 1 : 0.5) Text(tab.title).fontSize(11) .fontColor(this.currentTab idx ? tab.color : #999) .fontWeight(this.currentTab idx ? FontWeight.Medium : FontWeight.Regular) } .layoutWeight(1) .padding({ top: 6, bottom: 6 }) .onClick(() { this.currentTab idx }) }) } .width(100%).height(64) .backgroundColor(#fff) .borderRadius({ topLeft: 16, topRight: 16 }) .shadow({ radius: 8, color: #20000000, offsetY: -2 })導(dǎo)航欄的樣式設(shè)計(jì)屬性值說明高度64標(biāo)準(zhǔn)導(dǎo)航欄高度符合人體工學(xué)背景色#fff純白背景圓角{ topLeft: 16, topRight: 16 }僅頂部圓角與底部邊緣平滑過渡陰影offsetY: -2向上偏移產(chǎn)生「浮在內(nèi)容之上」的效果選中/未選中狀態(tài)對(duì)比樣式屬性未選中選中圖標(biāo)透明度0.51.0文字顏色#999灰色tab.color主題色文字字重RegularMedium這種「透明度顏色字重」的三重區(qū)分確保了選中狀態(tài)的清晰可辨同時(shí)保持了整體視覺的協(xié)調(diào)性。3.3 圓角與陰影的巧妙運(yùn)用.borderRadius({ topLeft: 16, topRight: 16 }) .shadow({ radius: 8, color: #20000000, offsetY: -2 })borderRadius 對(duì)象語法ArkUI 支持為四個(gè)角分別設(shè)置圓角半徑格式為{ topLeft, topRight, bottomLeft, bottomRight }。這里只設(shè)定了頂部?jī)蓚€(gè)角的圓角底部緊貼屏幕邊緣形成懸浮導(dǎo)航欄的效果。陰影向上偏移offsetY: -2表示陰影向上偏移 2vp配合radius: 8較大的模糊半徑產(chǎn)生導(dǎo)航欄「浮在內(nèi)容上方」的視覺效果。這與 Material Design 的 Bottom App Bar 設(shè)計(jì)語言一致。四、HarmonyOS 特色功能深度解析4.1 layoutWeight 彈性布局.layoutWeight(1)每個(gè) Tab 項(xiàng)都設(shè)置layoutWeight(1)在Row容器中等分寬度。無論屏幕寬度是 360vp 還是 428vp四個(gè) Tab 自動(dòng)平分底部空間。layoutWeight 的計(jì)算規(guī)則先分配所有未設(shè)置layoutWeight的組件的固定寬度剩余空間按layoutWeight值比例分配給設(shè)置了該屬性的組件如果所有子組件都設(shè)置了layoutWeight(1)則等分總寬度4.2 ForEach 的索引參數(shù)ForEach(this.tabs, (tab: TabItem, idx: number) { // idx 就是當(dāng)前項(xiàng)的索引 .onClick(() { this.currentTab idx }) })ForEach的回調(diào)函數(shù)可以接收兩個(gè)參數(shù)第一個(gè)參數(shù)數(shù)組中的元素值第二個(gè)參數(shù)元素在數(shù)組中的索引從 0 開始使用索引參數(shù)可以避免為每個(gè) Tab 手動(dòng)綁定onClick事件這是 ForEach 簡(jiǎn)化代碼的重要特性。4.3 Text 組件的多行內(nèi)容content: 歡迎來到底部導(dǎo)航演示\n\n這是首頁的內(nèi)容區(qū)域\n可以放置各種信息和功能卡片在Text組件中使用\n換行符可以實(shí)現(xiàn)多行文本顯示配合lineHeight屬性控制行間距。這是最簡(jiǎn)單的內(nèi)容換行方式不需要使用多個(gè)Text組件堆疊。五、UI/UX 設(shè)計(jì)分析5.1 四標(biāo)簽導(dǎo)航四個(gè)標(biāo)簽覆蓋了主流 App 的標(biāo)準(zhǔn)導(dǎo)航結(jié)構(gòu)標(biāo)簽圖標(biāo)主題色典型用途首頁#0077FF藍(lán)色內(nèi)容信息流發(fā)現(xiàn)#4CAF50綠色搜索/探索消息#FF9800橙色通知/聊天我的#9C27B0紫色個(gè)人中心色彩心理學(xué)四種主題色分別代表不同的功能屬性——藍(lán)色專業(yè)、綠色自然、橙色活躍、紫色創(chuàng)意。5.2 沉浸式導(dǎo)航欄設(shè)計(jì)底部導(dǎo)航欄的設(shè)計(jì)借鑒了現(xiàn)代移動(dòng)操作系統(tǒng)的設(shè)計(jì)語言懸浮效果白色背景 頂部圓角 向上陰影模擬物理懸浮觸控?zé)釁^(qū)padding({ top: 6, bottom: 6 })確保每個(gè) Tab 的點(diǎn)擊區(qū)域足夠大至少 44vp 的觸控高度視覺權(quán)重圖標(biāo) 22px 文字 11px圖標(biāo)視覺權(quán)重更大易于識(shí)別5.3 內(nèi)容區(qū)域設(shè)計(jì)內(nèi)容區(qū)域居中顯示大圖標(biāo)和歡迎文字圖標(biāo)fontSize(64)大尺寸圖標(biāo)形成視覺焦點(diǎn)文字lineHeight(28)舒適的閱讀行距textAlign(TextAlign.Center)居中排列六、最佳實(shí)踐與優(yōu)化建議6.1 當(dāng)前代碼亮點(diǎn)極簡(jiǎn)狀態(tài)管理僅用currentTab一個(gè)變量完成全部切換邏輯數(shù)據(jù)驅(qū)動(dòng) UI所有顯示內(nèi)容來自tabs數(shù)組新增標(biāo)簽只需修改數(shù)據(jù)導(dǎo)航欄懸浮設(shè)計(jì)圓角 陰影營(yíng)造沉浸視覺體驗(yàn)Tab 等分布局layoutWeight(1)實(shí)現(xiàn)自適應(yīng)寬度6.2 可優(yōu)化方向// 優(yōu)化建議 1頁面切換動(dòng)畫 // 使用 transition 添加頁面切換動(dòng)畫 Column() .transition({ type: TransitionType.Insert, translate: { x: 100 } }) .transition({ type: TransitionType.Delete, translate: { x: -100 } }) // 優(yōu)化建議 2使用 Tabs 組件替代手動(dòng)構(gòu)建 // HarmonyOS 提供了 Tabs TabContent 原生組件 Tabs() { TabContent() { /* 首頁內(nèi)容 */ }.tabBar( 首頁) TabContent() { /* 發(fā)現(xiàn)內(nèi)容 */ }.tabBar( 發(fā)現(xiàn)) TabContent() { /* 消息內(nèi)容 */ }.tabBar( 消息) TabContent() { /* 我的內(nèi)容 */ }.tabBar( 我的) } .barPosition(BarPosition.End) // 導(dǎo)航欄在底部 // 優(yōu)化建議 3角標(biāo)通知 // 在 Tab 圖標(biāo)上顯示未讀數(shù)量 Stack() { Text(tab.icon).fontSize(22) if (unreadCount 0) { Text(unreadCount 99 ? 99 : unreadCount.toString()) .fontSize(10).fontColor(#fff) .backgroundColor(#F44336).borderRadius(8) .padding({ left: 4, right: 4 }).height(16) .align(Alignment.TopEnd) } } // 優(yōu)化建議 4頁面緩存 // 使用 State 保存每個(gè) Tab 的滾動(dòng)位置 State scrollPositions: number[] [0, 0, 0, 0]; // 優(yōu)化建議 5導(dǎo)航欄隱藏/顯示 // 根據(jù)內(nèi)容滾動(dòng)方向自動(dòng)隱藏/顯示導(dǎo)航欄 State navBarVisible: boolean true;6.3 性能優(yōu)化Tab 數(shù)量控制底部導(dǎo)航建議不超過 5 個(gè) TabMaterial Design 規(guī)范超過時(shí)需使用「更多」折疊或滾動(dòng)模式內(nèi)容懶加載當(dāng)前實(shí)現(xiàn)中 4 個(gè) Tab 的內(nèi)容同時(shí)存在通過currentTab控制顯示對(duì)于內(nèi)容較重的頁面應(yīng)使用懶加載圖標(biāo)性能使用 emoji 而非圖片圖標(biāo)減少資源加載開銷七、總結(jié)與擴(kuò)展底部導(dǎo)航應(yīng)用展示了 ArkUI 中實(shí)現(xiàn) Tab 導(dǎo)航的核心模式知識(shí)點(diǎn)應(yīng)用位置重要程度State 狀態(tài)驅(qū)動(dòng)currentTab 切換★★★★★layoutWeight 彈性布局Tab 等分★★★★★ForEach 索引參數(shù)onClick 事件綁定★★★★☆borderRadius 對(duì)象語法導(dǎo)航欄圓角★★★☆☆shadow 陰影懸浮效果★★★☆☆擴(kuò)展思路與 Tabs 組件對(duì)比學(xué)習(xí) HarmonyOS 原生Tabs組件的 API了解手動(dòng)構(gòu)建與原生組件的權(quán)衡中間大按鈕部分 App 在底部導(dǎo)航欄中間放置大按鈕如發(fā)帖按鈕可通過Stack布局實(shí)現(xiàn)導(dǎo)航欄顏色跟隨根據(jù)所在 Tab 的主題色改變導(dǎo)航欄顏色返回?cái)r截配合onBackPress實(shí)現(xiàn)雙擊退出或確認(rèn)提示跨頁面狀態(tài)保持使用AppStorage在頁面切換時(shí)保持 Tab 狀態(tài)手勢(shì)切換添加左右滑動(dòng)手勢(shì)SwipeGesture切換 Tab底部導(dǎo)航是現(xiàn)代移動(dòng)應(yīng)用的標(biāo)準(zhǔn)導(dǎo)航模式。通過這個(gè)案例你不僅學(xué)會(huì)了如何構(gòu)建底部導(dǎo)航欄更理解了狀態(tài)驅(qū)動(dòng)的本質(zhì)——一個(gè)數(shù)字的變化驅(qū)動(dòng)整個(gè)頁面的重新渲染。這就是聲明式 UI 的核心思想U(xiǎn)I 是狀態(tài)的函數(shù)。