Flutter项目需求:搜索模式下隐藏SliverAppBar右侧操作按钮
我来帮你解决这个问题!要实现激活搜索模式时隐藏SliverAppBar右侧的action按钮,核心是让父组件(HomePage)能感知到SearchBar的搜索状态变化,然后根据这个状态控制按钮的显示。下面是具体的实现步骤和修改后的代码:
1. 把HomePage改为StatefulWidget
因为需要维护搜索激活状态,所以先将原本的StatelessWidget改为StatefulWidget,添加本地状态变量来跟踪搜索模式是否激活。
2. 给SearchBar添加状态回调
在SearchBar的构造函数中新增一个回调参数,用于将搜索状态变化通知给父组件。
3. 在SearchBar中触发状态回调
当搜索模式激活或取消时,调用回调函数把状态传递给HomePage。
4. 根据状态控制action按钮显示
在HomePage的SliverAppBar中,根据搜索状态决定是否渲染右侧的action按钮。
修改后的完整代码片段:
首先是HomePage部分:
class HomePage extends StatefulWidget with NavigationStates { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { // 跟踪搜索模式是否激活 bool _isSearchActive = false; @override Widget build(BuildContext context) { final sliverAppBar = SliverAppBar( pinned: true, expandedHeight: 140.0, backgroundColor: Theme.of(context).primaryColor, flexibleSpace: FlexibleSpaceBar( title: Text( AppStrings.homeTitle, style: Theme.of(context).textTheme.title.copyWith( color: CustomColors().novaWhite, ), ), background: Column( children: <Widget>[ SearchBar( canSearch: true, // 添加回调接收搜索状态变化 onSearchModeChanged: (isActive) { setState(() { _isSearchActive = isActive; }); }, ), ], ), ), // 根据搜索状态动态显示/隐藏action按钮 actions: _isSearchActive ? [] : <Widget>[ IconButton( icon: Icon(Icons.filter_list), color: CustomColors().novaWhite, onPressed: () {}, ), IconButton( icon: Icon(Icons.more_vert), color: CustomColors().novaWhite, onPressed: () {}, ), ], ); final pageContent = SafeArea( bottom: false, child: CustomScrollView( slivers: <Widget>[ sliverAppBar, SliverToBoxAdapter( child: Container( height: MediaQuery.of(context).size.height, padding: EdgeInsets.all(Constants.paddingXY_32), decoration: BoxDecoration( color: Theme.of(context).scaffoldBackgroundColor, ), // Page content begins here... ), ), ], ), ); return Scaffold( body: pageContent, backgroundColor: Theme.of(context).primaryColor, ); } }
然后是SearchBar部分:
class SearchBar extends StatefulWidget implements PreferredSizeWidget { final bool canSearch; // 新增回调参数,用于通知父组件搜索状态变化 final ValueChanged<bool> onSearchModeChanged; const SearchBar({ Key key, this.canSearch = false, @required this.onSearchModeChanged, }) : super(key: key); @override Size get preferredSize => Size.fromHeight(56.0); @override _SearchBar createState() => _SearchBar(); } class _SearchBar extends State<SearchBar> with SingleTickerProviderStateMixin { double rippleStartX, rippleStartY; AnimationController _controller; Animation _animation; bool isInSearchMode = false; @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 500)); _animation = Tween(begin: 0.0, end: 1.0).animate(_controller); _controller.addStatusListener(animationStatusListener); } void animationStatusListener(AnimationStatus animationStatus) { if (animationStatus == AnimationStatus.completed) { setState(() { isInSearchMode = true; }); // 通知父组件:搜索模式已激活 widget.onSearchModeChanged(true); } } void onSearchTapUp(TapUpDetails details) { setState(() { rippleStartX = details.globalPosition.dx; rippleStartY = details.globalPosition.dy; }); print("pointer location $rippleStartX, $rippleStartY"); _controller.forward(); } void cancelSearch() { setState(() { isInSearchMode = false; }); onSearchQueryChange(''); _controller.reverse(); // 通知父组件:搜索模式已取消 widget.onSearchModeChanged(false); } void onSearchQueryChange(String query) { print('search $query'); } @override Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; return Stack( children: <Widget>[ AppBar( elevation: 0.0, backgroundColor: Theme.of(context).primaryColor, leading: widget.canSearch ? GestureDetector( child: IconButton( icon: Icon( Icons.search, color: CustomColors().novaWhite, ), onPressed: null, ), onTapUp: onSearchTapUp, ) : Container(), ), AnimatedBuilder( animation: _animation, builder: (context, child) { return CustomPaint( painter: Painter( containerHeight: widget.preferredSize.height, center: Offset(rippleStartX ?? 0, rippleStartY ?? 0), radius: _animation.value * screenWidth, context: context, ), ); }, ), isInSearchMode ? Search( onCancelSearch: cancelSearch, onSearchQueryChanged: onSearchQueryChange, ) : Container() ], ); } }
这个方案通过组件间回调的方式实现了状态通信,逻辑简单直接,适合当前的场景。如果后续你的项目状态管理需求更复杂,也可以考虑使用Provider、Riverpod等状态管理库来优化,但这个方案已经能完美解决你当前的问题了。
内容的提问来源于stack exchange,提问作者Jonas
相关产品推荐
相关产品推荐

