Flutter BottomNavigationBar仿iPhone Dock样式实现求助
问题描述
当前底部导航栏:白色背景、顶部圆角、带阴影的常规底部导航
想要实现类似iPhone Dock的底部导航栏:半透明模糊背景、顶部圆角、左右带边距的悬浮式导航栏
我正在开发Flutter应用,已实现带自定义AppBar的BottomNavigationBar,以下是HomePage组件代码:
import 'package:flutter/material.dart'; import 'dart:ui'; // For ImageFilter.blur import 'screens/profile.dart'; import 'home_screen.dart'; import 'book_appointment.dart'; import 'screens/history.dart'; class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int _bottomNavIndex = 0; final List<Widget> _pages = [ HomeScreen(), AppointmentPage(), HistoryPage(), ]; final List<IconData> _iconList = [ Icons.home_filled, Icons.add_rounded, Icons.history, ]; final List<String> _titleList = [ 'Home', 'Appointments', 'History', ]; PreferredSizeWidget? _buildAppBar() { if (_bottomNavIndex == 0) { return PreferredSize( preferredSize: Size.fromHeight(60), child: AppBar( backgroundColor: Colors.transparent, flexibleSpace: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage('assets/appbar.png'), fit: BoxFit.cover, ), ), ), title: GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute(builder: (context) => ProfilePage()), ); }, child: Row( children: [ Padding( padding: EdgeInsets.only(top: 10), child: CircleAvatar( backgroundImage: AssetImage('assets/pogisivenz.png'), radius: 20, ), ), SizedBox(width: 10), Text( 'Hi, Harold Pogi', style: TextStyle(color: Color(0xFFE5D9F2)), ), ], ), ), ), ); } return null; } Widget _buildBottomNavigationBar() { return Container( decoration: BoxDecoration( color: Colors.white, // Background color for the dock borderRadius: BorderRadius.vertical( top: Radius.circular(30), // Rounded corners at the top ), boxShadow: [ BoxShadow(color: Colors.black38, spreadRadius: 0, blurRadius: 10), ], ), margin: const EdgeInsets.only(bottom: 20.0), // Margin for the floating effect child: ClipRRect( borderRadius: BorderRadius.vertical( top: Radius.circular(30), // Match the top rounded corners ), child: BottomNavigationBar( items: <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(_iconList[0]), label: _titleList[0], ), BottomNavigationBarItem( icon: Icon(_iconList[1]), label: _titleList[1], ), BottomNavigationBarItem( icon: Icon(_iconList[2]), label: _titleList[2], ), ], currentIndex: _bottomNavIndex, selectedItemColor: const Color.fromARGB(255, 116, 23, 133), unselectedItemColor: Colors.black, onTap: (index) { setState(() { _bottomNavIndex = index; }); }, ), ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.transparent, // Make Scaffold background transparent appBar: _buildAppBar(), body: Stack( children: [ Positioned.fill( child: Image.asset( 'assets/splash.png', fit: BoxFit.cover, ), ), Positioned.fill( child: AnimatedSwitcher( duration: Duration(milliseconds: 300), child: _pages[_bottomNavIndex], ), ), ], ), bottomNavigationBar: _buildBottomNavigationBar(), ); } }
多次修改后仍无法实现目标效果,该如何解决?
解决方案
直接修改以下核心部分即可实现iPhone Dock样式:
1. 替换为模糊半透明背景
iPhone Dock的核心是半透明模糊效果,用BackdropFilter替换原来的纯色背景,同时调整边距让导航栏更窄:
Widget _buildBottomNavigationBar() { return Container( // 左右加边距,让导航栏宽度小于屏幕宽度,贴近iOS风格 margin: const EdgeInsets.symmetric(horizontal: 20, bottom: 20), child: ClipRRect( borderRadius: BorderRadius.vertical(top: Radius.circular(30)), child: BackdropFilter( // 模糊程度可根据需求调整sigma值 filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12), child: Container( decoration: BoxDecoration( // 半透明白色,配合模糊效果呈现毛玻璃质感 color: Colors.white.withOpacity(0.75), borderRadius: BorderRadius.vertical(top: Radius.circular(30)), // 调整阴影方向,增强悬浮感 boxShadow: [ BoxShadow( color: Colors.black12, blurRadius: 8, offset: Offset(0, -2), ), ], ), child: BottomNavigationBar( // 固定模式,避免图标因数量变化移位 type: BottomNavigationBarType.fixed, // 取消导航栏自带背景色,让模糊效果透出来 backgroundColor: Colors.transparent, // 取消自带阴影,用自定义的阴影效果 elevation: 0, items: <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(_iconList[0]), label: _titleList[0], ), // 可选:给中间加号图标添加背景,突出显示 BottomNavigationBarItem( icon: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: const Color.fromARGB(255, 116, 23, 133), borderRadius: BorderRadius.circular(50), ), child: Icon(_iconList[1], color: Colors.white, size: 28), ), label: _titleList[1], ), BottomNavigationBarItem( icon: Icon(_iconList[2]), label: _titleList[2], ), ], currentIndex: _bottomNavIndex, selectedItemColor: const Color.fromARGB(255, 116, 23, 133), // 未选中图标用浅黑色,更贴近iOS视觉风格 unselectedItemColor: Colors.black54, onTap: (index) { setState(() { _bottomNavIndex = index; }); }, ), ), ), ), ); }
2. 解决页面内容被遮挡问题
设置extendBody: true让页面内容延伸到导航栏下方,配合模糊背景更自然:
@override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.transparent, // 关键:让body延伸到底部导航栏下方 extendBody: true, appBar: _buildAppBar(), body: Stack( children: [ Positioned.fill( child: Image.asset( 'assets/splash.png', fit: BoxFit.cover, ), ), Positioned.fill( child: AnimatedSwitcher( duration: Duration(milliseconds: 300), child: _pages[_bottomNavIndex], ), ), ], ), bottomNavigationBar: _buildBottomNavigationBar(), ); }
3. 细节优化(可选)
- 如果页面内容底部需要避开导航栏,可以给
_pages中的每个页面添加Padding(bottom: kBottomNavigationBarHeight + 20) - 调整模糊的
sigmaX/Y值可以改变毛玻璃的模糊程度,数值越大越模糊
完成以上修改后,底部导航栏就会具备iPhone Dock的悬浮模糊、顶部圆角、窄边距等特征,和目标效果一致。
内容的提问来源于stack exchange,提问作者Aiusu
相关产品推荐
相关产品推荐

