// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../../core/theme/app_colors.dart'; import '../../../l10n/app_localizations.dart'; const double _searchHeight = 40; const double _searchRadius = 20; const Duration _focusTransition = Duration(milliseconds: 160); /// 剧场顶部整行搜索框:白底细边,聚焦时主题色描边与更深的阴影。 class DiscoverSearchField extends StatefulWidget { const DiscoverSearchField({ super.key, required this.controller, required this.focusNode, required this.onChanged, required this.loading, this.horizontalPadding = 14, }); final TextEditingController controller; final FocusNode focusNode; final ValueChanged onChanged; final bool loading; final double horizontalPadding; @override State createState() => _DiscoverSearchFieldState(); } class _DiscoverSearchFieldState extends State { bool _focused = false; @override void initState() { super.initState(); widget.focusNode.addListener(_onFocusChanged); } @override void didUpdateWidget(covariant DiscoverSearchField oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.focusNode != widget.focusNode) { oldWidget.focusNode.removeListener(_onFocusChanged); widget.focusNode.addListener(_onFocusChanged); _focused = widget.focusNode.hasFocus; } } @override void dispose() { widget.focusNode.removeListener(_onFocusChanged); super.dispose(); } void _onFocusChanged() { final focused = widget.focusNode.hasFocus; if (focused != _focused) setState(() => _focused = focused); } @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.symmetric(horizontal: widget.horizontalPadding), child: AnimatedContainer( key: const Key('discover-search-shell'), duration: _focusTransition, curve: Curves.easeOut, height: _searchHeight, decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_searchRadius), border: Border.all( color: _focused ? AppColors.blue : AppColors.border, ), boxShadow: [ BoxShadow( color: _focused ? AppColors.blue.withValues(alpha: 0.18) : Colors.black.withValues(alpha: 0.04), blurRadius: _focused ? 10 : 4, offset: const Offset(0, 2), ), ], ), child: TextField( key: const Key('discover-search'), controller: widget.controller, focusNode: widget.focusNode, onChanged: widget.onChanged, onTapOutside: (_) => widget.focusNode.unfocus(), textInputAction: TextInputAction.search, style: const TextStyle(color: AppColors.onSurface, fontSize: 14), decoration: InputDecoration( isDense: true, filled: false, hintText: AppLocalizations.of(context)!.searchDiscover, hintStyle: const TextStyle(color: AppColors.subtle, fontSize: 13.5), prefixIcon: const Icon( Icons.search_rounded, color: AppColors.subtle, size: 17, ), suffixIcon: widget.loading ? const SizedBox.square( dimension: 18, child: Center( child: CircularProgressIndicator(strokeWidth: 2), ), ) : null, suffixIconConstraints: const BoxConstraints( minWidth: 0, minHeight: 0, ), contentPadding: const EdgeInsets.symmetric(horizontal: 12), border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, ), ), ), ); } }