Flutter中如何通过onTap事件修改AppBar背景颜色?
解决Flutter中通过ListTile点击修改SliverAppBar背景色的问题
你的代码无法生效的核心原因是:在setState里直接创建AppBar组件完全不会影响当前界面上的SliverAppBar——Flutter的UI是由状态驱动的,必须通过更新状态变量,让build方法重新执行来刷新界面。
具体修复步骤:
- 在
_MyHomePageState类中添加一个存储AppBar背景色的状态变量:
Color? _appBarBackgroundColor;
- 在
SliverAppBar组件中,把backgroundColor属性绑定到这个变量:
SliverAppBar( pinned: _pinned, snap: _snap, floating: _floating, expandedHeight: 160.0, backgroundColor: _appBarBackgroundColor, // 绑定背景色变量 flexibleSpace: FlexibleSpaceBar( // 原有代码保持不变 ), // 原有代码保持不变 )
- 修改各个颜色选项的
ListTile的onTap方法,更新状态变量并触发UI刷新:
// Black选项的ListTile ListTile( title: const Text('Black'), leading: const Icon(Icons.label), onTap: () { setState(() { _appBarBackgroundColor = Colors.black; }); Navigator.pop(context); }, ), // Grey选项的ListTile ListTile( title: const Text('Grey'), leading: const Icon(Icons.label), onTap: () { setState(() { _appBarBackgroundColor = Colors.grey; }); Navigator.pop(context); }, ), // Blue选项的ListTile ListTile( title: const Text('Blue'), leading: const Icon(Icons.label), onTap: () { setState(() { _appBarBackgroundColor = Colors.blue; }); Navigator.pop(context); }, ),
完整修改后的_MyHomePageState类代码:
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { final bool _pinned = true; final bool _snap = true; final bool _floating = true; late TabController controller; int _selectedIndex = 0; final ScrollController _homeController = ScrollController(); Color? _appBarBackgroundColor; // 新增状态变量 @override void initState() { super.initState(); controller = TabController( length: 2, vsync: this, ); } @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: <Widget>[ SliverAppBar( pinned: _pinned, snap: _snap, floating: _floating, expandedHeight: 160.0, backgroundColor: _appBarBackgroundColor, // 绑定背景色 flexibleSpace: FlexibleSpaceBar( title: const Text( 'UTS - KARYAWAN', style: TextStyle(color: Colors.black), ), centerTitle: true, background: Image( image: NetworkImage( 'https://hariliburnasional.com/wp-content/uploads/2020/10/Tempat-Wisata-di-Bali.jpg'), fit: BoxFit.cover, ), collapseMode: CollapseMode.pin, ), bottom: TabBar( tabs: const [ Tab(icon: Icon(Icons.two_wheeler)), Tab(icon: Icon(Icons.directions_car)), ], controller: controller, ), ), SliverFillRemaining( child: TabBarView( controller: controller, children: const [ Image( image: NetworkImage( 'https://cdn.autoportal.com/bp-v3/img/models/49/e/ducati-1299-panigale-r-final-edition-14.jpg'), fit: BoxFit.cover, ), Image( image: AssetImage('assets/images/toyota_supra.jpg'), fit: BoxFit.cover, ), ], ), ), ], ), // DRAWER NAV drawer: Drawer( child: ListView( padding: EdgeInsets.zero, children: [ const UserAccountsDrawerHeader( accountName: Text('Muh Hilman Sholehudin'), accountEmail: Text('ahilman3107@gmail.com'), currentAccountPicture: CircleAvatar( foregroundImage: AssetImage('assets/images/hilman.png')), otherAccountsPictures: [ CircleAvatar( foregroundImage: AssetImage('assets/images/hilman.png')), CircleAvatar( foregroundImage: AssetImage('assets/images/hilman.png')), ], ), ListTile( title: const Text('Home'), leading: const Icon(Icons.home), onTap: () => { Navigator.of(context).push( MaterialPageRoute( builder: (context) => const SecondRoute(), ), ), }, ), ListTile( title: const Text('Favorite'), leading: const Icon(Icons.favorite_border), onTap: () { Navigator.pop(context); }, ), const Padding( padding: EdgeInsets.all(14.0), child: Text('Label'), ), ListTile( title: const Text('Black'), leading: const Icon(Icons.label), onTap: () { setState(() { _appBarBackgroundColor = Colors.black; }); Navigator.pop(context); }, ), ListTile( title: const Text('Grey'), leading: const Icon(Icons.label), onTap: () { setState(() { _appBarBackgroundColor = Colors.grey; }); Navigator.pop(context); }, ), ListTile( title: const Text('Blue'), leading: const Icon(Icons.label), onTap: () { setState(() { _appBarBackgroundColor = Colors.blue; }); Navigator.pop(context); }, ), ], ), ), // BOTTOM NAVIBAR bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.open_in_new_rounded), label: 'Open Dialog', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.blue, onTap: (int index) { switch (index) { case 0: if (_selectedIndex == index) { _homeController.animateTo( 0.0, duration: const Duration(milliseconds: 500), curve: Curves.easeOut, ); } break; case 1: showModal(context); break; } setState( () { _selectedIndex = index; }, ); }, ), ); } void showModal(BuildContext context) { showDialog( context: context, builder: (BuildContext context) => AlertDialog( content: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: const <Widget>[ Text("NIM : 19255024"), Text("Nama : Muh Hilman Sholehudin"), Text("Kelas : Karyawan") ], ), actions: <TextButton>[ TextButton( onPressed: () { Navigator.pop(context); }, child: const Text('Close'), ) ], ), ); } }
这样修改后,点击抽屉里的颜色选项,就能实时更新SliverAppBar的背景色了。
内容的提问来源于stack exchange,提问作者Muh Hilman
相关产品推荐
相关产品推荐

