Flutter开发:为SliverAppBar折叠区添加组件及渐变背景
解决方案
1. 解决Leading溢出与位置冲突问题
直接移除SliverAppBar的leading和leadingWidth属性,将返回按钮嵌入flexibleSpace的Stack布局中,通过Align控制在左上角位置,并适配状态栏内边距,避免按钮被遮挡。这种方式完全规避了原生leading区域的空间限制,不会和FlexibleSpaceBar内容重叠。
2. 实现渐变背景效果
在背景图片上层叠加带渐变的容器,通过LinearGradient自定义渐变方向、颜色和透明度,你可以根据需求调整渐变参数。
3. 折叠状态中心添加组件
- 将原
StatelessWidget改为StatefulWidget,通过NotificationListener监听滚动事件,计算滚动进度(0为完全展开,1为完全折叠)。 - 在
Stack中添加居中组件,用Opacity绑定滚动进度,实现折叠时显示、展开时隐藏的平滑过渡效果。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:rehove/Widgets/sliver_card.dart'; import '../Widgets/action_button.dart'; class UserScreen extends StatefulWidget { const UserScreen({Key? key}) : super(key: key); @override State<UserScreen> createState() => _UserScreenState(); } class _UserScreenState extends State<UserScreen> { double _scrollProgress = 0.0; @override Widget build(BuildContext context) { TextTheme _textTheme = Theme.of(context).textTheme; final expandedHeight = 450.0; final collapsedHeight = 320.0; final scrollRange = expandedHeight - collapsedHeight; return AnnotatedRegion<SystemUiOverlayStyle>( value: const SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light ), child: Scaffold( body: NotificationListener<ScrollNotification>( onNotification: (notification) { final scrollPosition = notification.metrics.pixels; setState(() { _scrollProgress = (scrollPosition.clamp(0.0, scrollRange) / scrollRange).clamp(0.0, 1.0); }); return false; }, child: CustomScrollView( slivers: [ SliverAppBar( collapsedHeight: collapsedHeight, pinned: true, expandedHeight: expandedHeight, flexibleSpace: FlexibleSpaceBar( background: Stack( fit: StackFit.expand, children: [ // 背景图片 Image.asset( 'assets/images/user.png', fit: BoxFit.cover, ), // 渐变叠加层 Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.transparent, Color(0xff1a73e8).withOpacity(0.8), ], ), ), ), // 自定义返回按钮 Align( alignment: Alignment.topLeft, child: Padding( padding: EdgeInsets.only( left: 32, top: MediaQuery.of(context).padding.top + 16, ), child: GestureDetector( onTap: () => Navigator.pop(context), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.arrow_back_ios, color: Colors.white), SizedBox(width: 8), Text( 'Back', style: _textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, fontSize: 16, color: Colors.white, ), ), ], ), ), ), ), // 折叠状态中心组件 Align( alignment: Alignment.center, child: Opacity( opacity: _scrollProgress, child: Container( width: 60, height: 60, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( color: Colors.black12, blurRadius: 8, offset: Offset(0, 2), ), ], ), child: Icon(Icons.person, color: Color(0xff1a73e8), size: 32), ), ), ), // 底部信息栏 Align( alignment: Alignment.bottomCenter, child: Container( height: 102, width: double.infinity, color: Color(0xffD9D9D9).withOpacity(0.6), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Liya Dereje', style: _textTheme.bodyLarge?.copyWith( color: Color(0xffffffff), fontWeight: FontWeight.w500, fontSize: 20, ), ), Text( 'LiyaDereje2@gmail.com', style: _textTheme.bodyLarge?.copyWith( color: Color(0xfff7f7f7), fontWeight: FontWeight.w500, fontSize: 12, ), ), ], ), ActionButton( label: 'Edit Profile', height: 38, width: 120, onPressed: () {}, ), ], ), ), ), ), ], ), ), ), // 设置列表区域 SliverToBoxAdapter( child: Column( children: [ const SizedBox(height: 40), Row( children: [ const Expanded(child: Divider(thickness: 1)), Text( 'Setting', style: _textTheme.bodySmall?.copyWith( fontSize: 14, fontWeight: FontWeight.w400, ), ), const Expanded(child: Divider(thickness: 1)), ], ), const SizedBox(height: 16), SliverCard(icon: Icons.notifications_outlined, title: 'Notification', amount: '4'), const SizedBox(height: 10), SliverCard(icon: Icons.donut_small, title: 'Reports', amount: '4'), const SizedBox(height: 10), SliverCard(icon: Icons.email_outlined, title: 'Email', amount: '5'), const SizedBox(height: 10), SliverCard(icon: Icons.description_outlined, title: 'Terms of', amount: '3'), const SizedBox(height: 10), SliverCard(icon: Icons.accessibility_new_rounded, title: 'Accessibility', amount: '4'), const SizedBox(height: 10), SliverCard(icon: Icons.logout, title: 'Logout', amount: '4'), const SizedBox(height: 10), SliverCard(icon: Icons.email_outlined, title: 'Email', amount: '5'), const SizedBox(height: 10), SliverCard(icon: Icons.description_outlined, title: 'Terms of', amount: '3'), const SizedBox(height: 10), SliverCard(icon: Icons.accessibility_new_rounded, title: 'Accessibility', amount: '4'), const SizedBox(height: 10), ], ), ), ], ), ), ), ); } }
内容的提问来源于stack exchange,提问作者Nahom Ersom
相关产品推荐
相关产品推荐

