02. Flutter 鸿蒙实战 02Web 移植到 Flutter HarmonyOS 的页面结构把 Web 手机端的顶部栏、底部导航和业务入口迁移成 Flutter 页面骨架。迁移思路这个项目不是从零设计一套新 UI而是以 Web 手机端为基准迁移到 Flutter HarmonyOS。README.md里写得很直接界面与交互以现有 Web 手机端适配效果为基准不在迁移阶段重新设计。这个约束很重要意味着 Flutter 端的工作不是“自由发挥”而是把 Web 的信息层级、颜色、圆角、入口位置和导航方式稳定迁过来。项目中承担主框架职责的是lib/features/shell/app_shell.dart。它用一个StatefulWidget管理底部 Tab顶部 AppBar 放通知和个人资料入口中间 body 根据当前 Tab 切换页面。classAppShellextendsStatefulWidget{constAppShell({super.key,this.initialRoute});finalString?initialRoute;overrideStateAppShellcreateState()_AppShellState();}五项底部导航底部导航没有直接使用 Material 默认的胶囊样式而是手写_MobileBottomNav。这样做是为了更接近 Web 手机端的视觉白底、顶部分割线、选中项橙色、图标和文字上下排列。staticconst_destinations[_Destination(AppRoutes.home,首页,Icons.home_outlined),_Destination(AppRoutes.stories,故事,Icons.menu_book_outlined),_Destination(AppRoutes.upload,上传,Icons.upload_rounded),_Destination(AppRoutes.map,地图,Icons.location_on_outlined),_Destination(AppRoutes.anniversary,纪念日,Icons.calendar_month_outlined),];页面切换逻辑保持简单bottomNavigationBar:_MobileBottomNav(destinations:_destinations,selectedIndex:_selectedIndex,onSelected:(index)setState(()_selectedIndexindex),)这个写法不依赖路由栈切换主 Tab状态更直观。首页、故事、上传、地图、纪念日都是主功能点击底部导航时直接切换 body。首页入口联动首页不是孤立页面它把多个业务入口统一放到首屏上传照片、智能对话、照片活化、故事集、家族地图、添加家人。AppShell传入回调让首页按钮可以切换 Tab 或打开二级页面。0HomePage(onUploadPressed:()setState(()_selectedIndex2),onStoriesPressed:()setState(()_selectedIndex1),onMapPressed:()setState(()_selectedIndex3),onChatPressed:()_openPage(constChatPage()),onFamilyPressed:()_openPage(constFamilyPage()),),这段设计比较适合移动端上传、故事、地图属于主 Tab直接切过去对话和家人列表属于二级功能用Navigator.push打开。顶部栏和二级页面顶部栏右侧有通知和个人资料入口IconButton(tooltip:通知,onPressed:()_openPage(constNotificationsPage()),icon:constIcon(Icons.notifications_none_rounded,size:28),),PopupMenuButtonString(tooltip:个人资料,icon:constIcon(Icons.account_circle_outlined,size:29),onSelected:(value){if(valueprofile)_openPage(constProfilePage());if(valuelogout)AuthScope.of(context).logout();},)通知中心和个人资料不是底部主 Tab但它们是全局入口放在 AppBar 里更符合使用习惯。退出登录直接调用AuthScope.of(context).logout()会清除本地会话并回到登录页。页面迁移时最容易忽略的点Web 到 Flutter 的迁移不能只看颜色。移动端页面还要关注安全区、底部导航遮挡、长列表滚动、返回栈和弹层高度。这个项目的主页面列表普遍使用类似下面的 paddingListView(padding:constEdgeInsets.fromLTRB(16,16,16,112),children:[...])底部预留112就是为了避免内容被底部导航挡住。这个细节如果漏掉页面底部按钮或列表最后一项会被导航栏盖住。扩展拆解迁移页面时要避免的几个问题Web 页面迁移到 Flutter 时最容易犯的错误是只盯着截图颜色忽略移动端交互。这个项目的首页、故事页、上传页都使用长列表底部又有固定导航所以内容区域必须预留底部空间。否则最后一个按钮或列表项会被导航栏遮住。主 Tab 用setState切换二级页面用Navigator.push这是比较清晰的移动端层级。主 Tab 代表长期存在的功能区二级页代表临时任务例如通知、个人资料、家人列表、智能对话。这样的层级让返回行为更自然从个人资料返回首页而不是在几个 Tab 之间倒退。body:switch(_selectedIndex){0HomePage(...),1constStoriesPage(),2UploadPage(onUploaded:()setState(()_selectedIndex0)),3constMapPage(),4constAnniversaryPage(),_FeaturePlaceholderPage(...),}tedIndex 0)),3 const MapPage(),4 const AnniversaryPage(),_ FeaturePlaceholderPage(…),}这段代码不依赖复杂框架但足够实用用 Flutter 原生能力就能组织一个完整移动端应用。