// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../../core/theme/app_colors.dart'; import '../../../l10n/app_localizations.dart'; const double _searchHeight = 44; const double _searchRadius = 22; const double _searchPadding = 14; const double _iconSize = 18; const double _iconGap = 8; 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, padding: const EdgeInsets.symmetric(horizontal: _searchPadding), decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_searchRadius), border: Border.all( color: _focused ? AppColors.blue : Colors.transparent, ), ), child: Row( children: [ const Icon( Icons.search_rounded, color: AppColors.subtle, size: _iconSize, ), const SizedBox(width: _iconGap), Expanded( child: TextField( key: const Key('discover-search'), controller: widget.controller, focusNode: widget.focusNode, onChanged: widget.onChanged, onTapOutside: (_) => widget.focusNode.unfocus(), textInputAction: TextInputAction.search, textAlignVertical: TextAlignVertical.center, style: const TextStyle( color: AppColors.onSurface, fontSize: 14, ), decoration: InputDecoration( isDense: true, hintText: AppLocalizations.of(context)!.searchDiscover, hintStyle: const TextStyle( color: AppColors.subtle, fontSize: 14, ), border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, contentPadding: EdgeInsets.zero, suffixIcon: widget.loading ? const SizedBox.square( dimension: 18, child: Center( child: CircularProgressIndicator(strokeWidth: 2), ), ) : null, suffixIconConstraints: const BoxConstraints( minWidth: 0, minHeight: 0, ), ), ), ), ], ), ), ); } }