diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index 80ed77fc8a..ad41c02304 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -137,6 +137,7 @@ class SearchAnchor extends StatefulWidget { required this.suggestionsBuilder, this.textInputAction, this.keyboardType, + this.enabled = true, }); /// Create a [SearchAnchor] that has a [SearchBar] which opens a search view. @@ -350,6 +351,13 @@ class SearchAnchor extends StatefulWidget { /// Defaults to the default value specified in [TextField]. final TextInputType? keyboardType; + /// Whether or not this widget is currently interactive. + /// + /// When false, the widget will ignore taps and appear dimmed. + /// + /// Defaults to true. + final bool enabled; + @override State createState() => _SearchAnchorState(); } @@ -450,15 +458,25 @@ class _SearchAnchorState extends State { }; } + double _getOpacity() { + if (widget.enabled) { + return _anchorIsVisible ? 1.0 : 0.0; + } + return _kDisableSearchBarOpacity; + } + @override Widget build(BuildContext context) { return AnimatedOpacity( key: _anchorKey, - opacity: _anchorIsVisible ? 1.0 : 0.0, + opacity: _getOpacity(), duration: _kAnchorFadeDuration, - child: GestureDetector( - onTap: _openView, - child: widget.builder(context, _searchController), + child: IgnorePointer( + ignoring: !widget.enabled, + child: GestureDetector( + onTap: _openView, + child: widget.builder(context, _searchController), + ), ), ); } @@ -1317,7 +1335,11 @@ class SearchBar extends StatefulWidget { /// {@macro flutter.widgets.editableText.textCapitalization} final TextCapitalization? textCapitalization; - /// If false the text field is "disabled" so the SearchBar will ignore taps. + /// Whether or not this widget is currently interactive. + /// + /// When false, the widget will ignore taps and appear dimmed. + /// + /// Defaults to true. final bool enabled; /// {@macro flutter.widgets.editableText.autofocus} diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index 4d66a2a869..a3100b94e8 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -3016,6 +3016,56 @@ void main() { expect(opacityWidget.opacity, 0.38); }); + testWidgets('Check SearchAnchor opacity when disabled', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + home: Center( + child: Material( + child: SearchAnchor( + enabled: false, + builder: (BuildContext context, SearchController controller) { + return const Icon(Icons.search); + }, + suggestionsBuilder: (BuildContext context, SearchController controller) { + return []; + }, + ), + ), + ), + )); + + final Finder searchBarFinder = find.byType(SearchAnchor); + expect(searchBarFinder, findsOneWidget); + final Finder opacityFinder = find.descendant( + of: searchBarFinder, + matching: find.byType(AnimatedOpacity), + ); + expect(opacityFinder, findsOneWidget); + final AnimatedOpacity opacityWidget = tester.widget(opacityFinder); + expect(opacityWidget.opacity, 0.38); + }); + + testWidgets('SearchAnchor tap failed when disabled', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + home: Center( + child: Material( + child: SearchAnchor( + enabled: false, + builder: (BuildContext context, SearchController controller) { + return const Icon(Icons.search); + }, + suggestionsBuilder: (BuildContext context, SearchController controller) { + return []; + }, + ), + ), + ), + )); + + final Finder searchBarFinder = find.byType(SearchAnchor); + expect(searchBarFinder, findsOneWidget); + expect(searchBarFinder.hitTestable().tryEvaluate(), false); + }); + testWidgets('SearchAnchor respects headerHeight', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Center(