import 'package:flutter/material.dart'; /// 自定义应用栏 class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { final String title; final List? actions; final Widget? leading; final bool centerTitle; final Color? backgroundColor; final Color? foregroundColor; final double elevation; final bool automaticallyImplyLeading; final PreferredSizeWidget? bottom; final VoidCallback? onBackPressed; const CustomAppBar({ super.key, required this.title, this.actions, this.leading, this.centerTitle = true, this.backgroundColor, this.foregroundColor, this.elevation = 0, this.automaticallyImplyLeading = true, this.bottom, this.onBackPressed, }); @override Widget build(BuildContext context) { final theme = Theme.of(context); return AppBar( title: Text( title, style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w600, color: foregroundColor ?? theme.colorScheme.onSurface, ), ), centerTitle: centerTitle, backgroundColor: backgroundColor ?? theme.colorScheme.surface, foregroundColor: foregroundColor ?? theme.colorScheme.onSurface, elevation: elevation, automaticallyImplyLeading: automaticallyImplyLeading, leading: leading ?? (onBackPressed != null ? IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: onBackPressed, ) : null), actions: actions, bottom: bottom, surfaceTintColor: Colors.transparent, ); } @override Size get preferredSize => Size.fromHeight( kToolbarHeight + (bottom?.preferredSize.height ?? 0.0), ); } /// 带搜索功能的应用栏 class SearchAppBar extends StatefulWidget implements PreferredSizeWidget { final String title; final String hintText; final ValueChanged? onSearchChanged; final VoidCallback? onSearchSubmitted; final List? actions; final bool automaticallyImplyLeading; final VoidCallback? onBackPressed; const SearchAppBar({ super.key, required this.title, this.hintText = '搜索...', this.onSearchChanged, this.onSearchSubmitted, this.actions, this.automaticallyImplyLeading = true, this.onBackPressed, }); @override State createState() => _SearchAppBarState(); @override Size get preferredSize => const Size.fromHeight(kToolbarHeight); } class _SearchAppBarState extends State { bool _isSearching = false; final TextEditingController _searchController = TextEditingController(); final FocusNode _searchFocusNode = FocusNode(); @override void dispose() { _searchController.dispose(); _searchFocusNode.dispose(); super.dispose(); } void _startSearch() { setState(() { _isSearching = true; }); _searchFocusNode.requestFocus(); } void _stopSearch() { setState(() { _isSearching = false; _searchController.clear(); }); _searchFocusNode.unfocus(); widget.onSearchChanged?.call(''); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return AppBar( title: _isSearching ? TextField( controller: _searchController, focusNode: _searchFocusNode, decoration: InputDecoration( hintText: widget.hintText, border: InputBorder.none, hintStyle: theme.textTheme.bodyLarge?.copyWith( color: theme.colorScheme.onSurface.withOpacity(0.6), ), ), style: theme.textTheme.bodyLarge, onChanged: widget.onSearchChanged, onSubmitted: (_) => widget.onSearchSubmitted?.call(), ) : Text( widget.title, style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w600, ), ), centerTitle: !_isSearching, backgroundColor: theme.colorScheme.surface, foregroundColor: theme.colorScheme.onSurface, elevation: 0, automaticallyImplyLeading: widget.automaticallyImplyLeading && !_isSearching, leading: _isSearching ? IconButton( icon: const Icon(Icons.arrow_back), onPressed: _stopSearch, ) : (widget.onBackPressed != null ? IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: widget.onBackPressed, ) : null), actions: _isSearching ? [ IconButton( icon: const Icon(Icons.clear), onPressed: () { _searchController.clear(); widget.onSearchChanged?.call(''); }, ), ] : [ IconButton( icon: const Icon(Icons.search), onPressed: _startSearch, ), ...?widget.actions, ], surfaceTintColor: Colors.transparent, ); } } /// 带标签页的应用栏 class TabAppBar extends StatelessWidget implements PreferredSizeWidget { final String title; final List tabs; final TabController? controller; final List? actions; final bool automaticallyImplyLeading; final VoidCallback? onBackPressed; const TabAppBar({ super.key, required this.title, required this.tabs, this.controller, this.actions, this.automaticallyImplyLeading = true, this.onBackPressed, }); @override Widget build(BuildContext context) { final theme = Theme.of(context); return AppBar( title: Text( title, style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w600, ), ), centerTitle: true, backgroundColor: theme.colorScheme.surface, foregroundColor: theme.colorScheme.onSurface, elevation: 0, automaticallyImplyLeading: automaticallyImplyLeading, leading: onBackPressed != null ? IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: onBackPressed, ) : null, actions: actions, bottom: TabBar( controller: controller, tabs: tabs, labelColor: theme.colorScheme.primary, unselectedLabelColor: theme.colorScheme.onSurface.withOpacity(0.6), indicatorColor: theme.colorScheme.primary, indicatorWeight: 2, labelStyle: theme.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w600, ), unselectedLabelStyle: theme.textTheme.titleSmall, ), surfaceTintColor: Colors.transparent, ); } @override Size get preferredSize => const Size.fromHeight(kToolbarHeight + kTextTabBarHeight); }