forked from firka/flutter
Add constraint options to SearchAnchor suggestions builder (#148856)
Refactors the `SearchAnchor` suggestions builder to not take up the whole screen https://github.com/flutter/flutter/issues/148852
This commit is contained in:
@@ -50,6 +50,9 @@ class _${blockName}DefaultsM3 extends ${blockName}ThemeData {
|
||||
@override
|
||||
EdgeInsetsGeometry? get barPadding => const EdgeInsets.symmetric(horizontal: 8.0);
|
||||
|
||||
@override
|
||||
bool get shrinkWrap => false;
|
||||
|
||||
@override
|
||||
Color? get dividerColor => ${componentColor('md.comp.search-view.divider')};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'adaptive_text_selection_toolbar.dart';
|
||||
@@ -133,6 +134,7 @@ class SearchAnchor extends StatefulWidget {
|
||||
this.dividerColor,
|
||||
this.viewConstraints,
|
||||
this.viewPadding,
|
||||
this.shrinkWrap,
|
||||
this.textCapitalization,
|
||||
this.viewOnChanged,
|
||||
this.viewOnSubmitted,
|
||||
@@ -170,6 +172,7 @@ class SearchAnchor extends StatefulWidget {
|
||||
EdgeInsetsGeometry? viewBarPadding,
|
||||
MaterialStateProperty<TextStyle?>? barTextStyle,
|
||||
MaterialStateProperty<TextStyle?>? barHintStyle,
|
||||
ViewBuilder? viewBuilder,
|
||||
Widget? viewLeading,
|
||||
Iterable<Widget>? viewTrailing,
|
||||
String? viewHintText,
|
||||
@@ -184,6 +187,7 @@ class SearchAnchor extends StatefulWidget {
|
||||
BoxConstraints? constraints,
|
||||
BoxConstraints? viewConstraints,
|
||||
EdgeInsetsGeometry? viewPadding,
|
||||
bool? shrinkWrap,
|
||||
bool? isFullScreen,
|
||||
SearchController searchController,
|
||||
TextCapitalization textCapitalization,
|
||||
@@ -328,6 +332,14 @@ class SearchAnchor extends StatefulWidget {
|
||||
/// If null, the value of [SearchViewThemeData.padding] will be used.
|
||||
final EdgeInsetsGeometry? viewPadding;
|
||||
|
||||
/// Whether the search view should shrink-wrap its contents.
|
||||
///
|
||||
/// Has no effect if the search view is full-screen.
|
||||
///
|
||||
/// If null, the value of [SearchViewThemeData.shrinkWrap] will be used. If
|
||||
/// this is also null, then the default value is `false`.
|
||||
final bool? shrinkWrap;
|
||||
|
||||
/// {@macro flutter.widgets.editableText.textCapitalization}
|
||||
final TextCapitalization? textCapitalization;
|
||||
|
||||
@@ -454,6 +466,7 @@ class _SearchAnchorState extends State<SearchAnchor> {
|
||||
dividerColor: widget.dividerColor,
|
||||
viewConstraints: widget.viewConstraints,
|
||||
viewPadding: widget.viewPadding,
|
||||
shrinkWrap: widget.shrinkWrap,
|
||||
showFullScreenView: getShowFullScreenView(),
|
||||
toggleVisibility: toggleVisibility,
|
||||
textDirection: Directionality.of(context),
|
||||
@@ -536,6 +549,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
|
||||
this.dividerColor,
|
||||
this.viewConstraints,
|
||||
this.viewPadding,
|
||||
this.shrinkWrap,
|
||||
this.textCapitalization,
|
||||
required this.showFullScreenView,
|
||||
required this.anchorKey,
|
||||
@@ -566,6 +580,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
|
||||
final Color? dividerColor;
|
||||
final BoxConstraints? viewConstraints;
|
||||
final EdgeInsetsGeometry? viewPadding;
|
||||
final bool? shrinkWrap;
|
||||
final TextCapitalization? textCapitalization;
|
||||
final bool showFullScreenView;
|
||||
final GlobalKey anchorKey;
|
||||
@@ -690,7 +705,6 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
|
||||
|
||||
@override
|
||||
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||
|
||||
return Directionality(
|
||||
textDirection: textDirection ?? TextDirection.ltr,
|
||||
child: AnimatedBuilder(
|
||||
@@ -732,7 +746,9 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
|
||||
viewHeaderTextStyle: viewHeaderTextStyle,
|
||||
viewHeaderHintStyle: viewHeaderHintStyle,
|
||||
dividerColor: dividerColor,
|
||||
viewConstraints: viewConstraints,
|
||||
viewPadding: viewPadding,
|
||||
shrinkWrap: shrinkWrap,
|
||||
showFullScreenView: showFullScreenView,
|
||||
animation: curvedAnimation!,
|
||||
topPadding: topPadding,
|
||||
@@ -774,7 +790,9 @@ class _ViewContent extends StatefulWidget {
|
||||
this.viewHeaderTextStyle,
|
||||
this.viewHeaderHintStyle,
|
||||
this.dividerColor,
|
||||
this.viewConstraints,
|
||||
this.viewPadding,
|
||||
this.shrinkWrap,
|
||||
this.textCapitalization,
|
||||
required this.showFullScreenView,
|
||||
required this.topPadding,
|
||||
@@ -803,7 +821,9 @@ class _ViewContent extends StatefulWidget {
|
||||
final TextStyle? viewHeaderTextStyle;
|
||||
final TextStyle? viewHeaderHintStyle;
|
||||
final Color? dividerColor;
|
||||
final BoxConstraints? viewConstraints;
|
||||
final EdgeInsetsGeometry? viewPadding;
|
||||
final bool? shrinkWrap;
|
||||
final TextCapitalization? textCapitalization;
|
||||
final bool showFullScreenView;
|
||||
final double topPadding;
|
||||
@@ -911,19 +931,6 @@ class _ViewContentState extends State<_ViewContent> {
|
||||
viewListFadeOnIntervalCurve.dispose();
|
||||
}
|
||||
|
||||
Widget viewBuilder(Iterable<Widget> suggestions) {
|
||||
if (widget.viewBuilder == null) {
|
||||
return MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeTop: true,
|
||||
child: ListView(
|
||||
children: suggestions.toList()
|
||||
),
|
||||
);
|
||||
}
|
||||
return widget.viewBuilder!(suggestions);
|
||||
}
|
||||
|
||||
Future<void> updateSuggestions() async {
|
||||
if (searchValue != _controller.text) {
|
||||
searchValue = _controller.text;
|
||||
@@ -998,6 +1005,16 @@ class _ViewContentState extends State<_ViewContent> {
|
||||
?? viewTheme.barPadding
|
||||
?? viewDefaults.barPadding;
|
||||
|
||||
final BoxConstraints effectiveConstraints = widget.viewConstraints
|
||||
?? viewTheme.constraints
|
||||
?? viewDefaults.constraints!;
|
||||
final double minWidth = math.min(effectiveConstraints.minWidth, _viewRect.width);
|
||||
final double minHeight = math.min(effectiveConstraints.minHeight, _viewRect.height);
|
||||
|
||||
final bool effectiveShrinkWrap = widget.shrinkWrap
|
||||
?? viewTheme.shrinkWrap
|
||||
?? viewDefaults.shrinkWrap!;
|
||||
|
||||
final Widget viewDivider = DividerTheme(
|
||||
data: dividerTheme.copyWith(color: effectiveDividerColor),
|
||||
child: const Divider(height: 1),
|
||||
@@ -1007,9 +1024,13 @@ class _ViewContentState extends State<_ViewContent> {
|
||||
alignment: Alignment.topLeft,
|
||||
child: Transform.translate(
|
||||
offset: _viewRect.topLeft,
|
||||
child: SizedBox(
|
||||
width: _viewRect.width,
|
||||
height: _viewRect.height,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: minWidth,
|
||||
maxWidth: _viewRect.width,
|
||||
minHeight: minHeight,
|
||||
maxHeight: _viewRect.height,
|
||||
),
|
||||
child: Padding(
|
||||
padding: widget.showFullScreenView ? EdgeInsets.zero : (effectivePadding ?? EdgeInsets.zero),
|
||||
child: Material(
|
||||
@@ -1018,57 +1039,69 @@ class _ViewContentState extends State<_ViewContent> {
|
||||
color: effectiveBackgroundColor,
|
||||
surfaceTintColor: effectiveSurfaceTint,
|
||||
elevation: effectiveElevation,
|
||||
child: ClipRect(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: OverflowBox(
|
||||
alignment: Alignment.topLeft,
|
||||
maxWidth: math.min(widget.viewMaxWidth, _screenSize!.width),
|
||||
minWidth: 0,
|
||||
child: FadeTransition(
|
||||
opacity: viewIconsFadeCurve,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: widget.topPadding),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: SearchBar(
|
||||
autoFocus: true,
|
||||
constraints: headerConstraints ?? (widget.showFullScreenView ? BoxConstraints(minHeight: _SearchViewDefaultsM3.fullScreenBarHeight) : null),
|
||||
padding: WidgetStatePropertyAll<EdgeInsetsGeometry?>(effectiveBarPadding),
|
||||
leading: widget.viewLeading ?? defaultLeading,
|
||||
trailing: widget.viewTrailing ?? defaultTrailing,
|
||||
hintText: widget.viewHintText,
|
||||
backgroundColor: const MaterialStatePropertyAll<Color>(Colors.transparent),
|
||||
overlayColor: const MaterialStatePropertyAll<Color>(Colors.transparent),
|
||||
elevation: const MaterialStatePropertyAll<double>(0.0),
|
||||
textStyle: MaterialStatePropertyAll<TextStyle?>(effectiveTextStyle),
|
||||
hintStyle: MaterialStatePropertyAll<TextStyle?>(effectiveHintStyle),
|
||||
controller: _controller,
|
||||
onChanged: (String value) {
|
||||
widget.viewOnChanged?.call(value);
|
||||
updateSuggestions();
|
||||
},
|
||||
onSubmitted: widget.viewOnSubmitted,
|
||||
textCapitalization: widget.textCapitalization,
|
||||
textInputAction: widget.textInputAction,
|
||||
keyboardType: widget.keyboardType,
|
||||
),
|
||||
child: OverflowBox(
|
||||
alignment: Alignment.topLeft,
|
||||
maxWidth: math.min(widget.viewMaxWidth, _screenSize!.width),
|
||||
minWidth: 0,
|
||||
fit: OverflowBoxFit.deferToChild,
|
||||
child: FadeTransition(
|
||||
opacity: viewIconsFadeCurve,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: widget.topPadding),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: SearchBar(
|
||||
autoFocus: true,
|
||||
constraints: headerConstraints ?? (widget.showFullScreenView ? BoxConstraints(minHeight: _SearchViewDefaultsM3.fullScreenBarHeight) : null),
|
||||
padding: WidgetStatePropertyAll<EdgeInsetsGeometry?>(effectiveBarPadding),
|
||||
leading: widget.viewLeading ?? defaultLeading,
|
||||
trailing: widget.viewTrailing ?? defaultTrailing,
|
||||
hintText: widget.viewHintText,
|
||||
backgroundColor: const MaterialStatePropertyAll<Color>(Colors.transparent),
|
||||
overlayColor: const MaterialStatePropertyAll<Color>(Colors.transparent),
|
||||
elevation: const MaterialStatePropertyAll<double>(0.0),
|
||||
textStyle: MaterialStatePropertyAll<TextStyle?>(effectiveTextStyle),
|
||||
hintStyle: MaterialStatePropertyAll<TextStyle?>(effectiveHintStyle),
|
||||
controller: _controller,
|
||||
onChanged: (String value) {
|
||||
widget.viewOnChanged?.call(value);
|
||||
updateSuggestions();
|
||||
},
|
||||
onSubmitted: widget.viewOnSubmitted,
|
||||
textCapitalization: widget.textCapitalization,
|
||||
textInputAction: widget.textInputAction,
|
||||
keyboardType: widget.keyboardType,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!effectiveShrinkWrap || minHeight > 0 || widget.showFullScreenView || result.isNotEmpty) ...<Widget>[
|
||||
FadeTransition(
|
||||
opacity: viewDividerFadeCurve,
|
||||
child: viewDivider),
|
||||
Expanded(
|
||||
child: viewDivider,
|
||||
),
|
||||
Flexible(
|
||||
fit: (effectiveShrinkWrap && !widget.showFullScreenView) ? FlexFit.loose : FlexFit.tight,
|
||||
child: FadeTransition(
|
||||
opacity: viewListFadeOnIntervalCurve,
|
||||
child: viewBuilder(result),
|
||||
child: widget.viewBuilder == null
|
||||
? MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeTop: true,
|
||||
child: ListView(
|
||||
shrinkWrap: effectiveShrinkWrap,
|
||||
children: result.toList(),
|
||||
),
|
||||
)
|
||||
: widget.viewBuilder!(result),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1095,6 +1128,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
|
||||
super.viewBarPadding,
|
||||
MaterialStateProperty<TextStyle?>? barTextStyle,
|
||||
MaterialStateProperty<TextStyle?>? barHintStyle,
|
||||
super.viewBuilder,
|
||||
super.viewLeading,
|
||||
super.viewTrailing,
|
||||
String? viewHintText,
|
||||
@@ -1109,6 +1143,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
|
||||
BoxConstraints? constraints,
|
||||
super.viewConstraints,
|
||||
super.viewPadding,
|
||||
super.shrinkWrap,
|
||||
super.isFullScreen,
|
||||
super.searchController,
|
||||
super.textCapitalization,
|
||||
@@ -1716,6 +1751,9 @@ class _SearchViewDefaultsM3 extends SearchViewThemeData {
|
||||
@override
|
||||
EdgeInsetsGeometry? get barPadding => const EdgeInsets.symmetric(horizontal: 8.0);
|
||||
|
||||
@override
|
||||
bool get shrinkWrap => false;
|
||||
|
||||
@override
|
||||
Color? get dividerColor => _colors.outline;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ class SearchViewThemeData with Diagnosticable {
|
||||
this.constraints,
|
||||
this.padding,
|
||||
this.barPadding,
|
||||
this.shrinkWrap,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.headerHeight,
|
||||
@@ -87,6 +88,9 @@ class SearchViewThemeData with Diagnosticable {
|
||||
/// Overrides the value of the padding for [SearchAnchor.viewBarPadding]
|
||||
final EdgeInsetsGeometry? barPadding;
|
||||
|
||||
/// Overrides the value of the shrink wrap for [SearchAnchor.shrinkWrap].
|
||||
final bool? shrinkWrap;
|
||||
|
||||
/// Overrides the value of the divider color for [SearchAnchor.dividerColor].
|
||||
final Color? dividerColor;
|
||||
|
||||
@@ -104,6 +108,7 @@ class SearchViewThemeData with Diagnosticable {
|
||||
BoxConstraints? constraints,
|
||||
EdgeInsetsGeometry? padding,
|
||||
EdgeInsetsGeometry? barPadding,
|
||||
bool? shrinkWrap,
|
||||
Color? dividerColor,
|
||||
}) {
|
||||
return SearchViewThemeData(
|
||||
@@ -118,6 +123,7 @@ class SearchViewThemeData with Diagnosticable {
|
||||
constraints: constraints ?? this.constraints,
|
||||
padding: padding ?? this.padding,
|
||||
barPadding: barPadding ?? this.barPadding,
|
||||
shrinkWrap: shrinkWrap ?? this.shrinkWrap,
|
||||
dividerColor: dividerColor ?? this.dividerColor,
|
||||
);
|
||||
}
|
||||
@@ -139,6 +145,7 @@ class SearchViewThemeData with Diagnosticable {
|
||||
constraints: BoxConstraints.lerp(a?.constraints, b?.constraints, t),
|
||||
padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t),
|
||||
barPadding: EdgeInsetsGeometry.lerp(a?.barPadding, b?.barPadding, t),
|
||||
shrinkWrap: t < 0.5 ? a?.shrinkWrap : b?.shrinkWrap,
|
||||
dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t),
|
||||
);
|
||||
}
|
||||
@@ -156,6 +163,7 @@ class SearchViewThemeData with Diagnosticable {
|
||||
constraints,
|
||||
padding,
|
||||
barPadding,
|
||||
shrinkWrap,
|
||||
dividerColor,
|
||||
);
|
||||
|
||||
@@ -179,6 +187,7 @@ class SearchViewThemeData with Diagnosticable {
|
||||
&& other.constraints == constraints
|
||||
&& other.padding == padding
|
||||
&& other.barPadding == barPadding
|
||||
&& other.shrinkWrap == shrinkWrap
|
||||
&& other.dividerColor == dividerColor;
|
||||
}
|
||||
|
||||
@@ -196,6 +205,7 @@ class SearchViewThemeData with Diagnosticable {
|
||||
properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry?>('padding', padding, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry?>('barPadding', barPadding, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<bool?>('shrinkWrap', shrinkWrap, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color?>('dividerColor', dividerColor, defaultValue: null));
|
||||
}
|
||||
|
||||
|
||||
@@ -1188,9 +1188,9 @@ void main() {
|
||||
await tester.pumpWidget(buildSearchAnchor(platform));
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
final SizedBox sizedBox = tester.widget<SizedBox>(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
expect(sizedBox.width, 800.0);
|
||||
expect(sizedBox.height, 600.0);
|
||||
final Size size = tester.getSize(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(size.width, 800.0);
|
||||
expect(size.height, 600.0);
|
||||
}
|
||||
|
||||
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.linux, TargetPlatform.windows ]) {
|
||||
@@ -1198,9 +1198,9 @@ void main() {
|
||||
await tester.pumpWidget(buildSearchAnchor(platform));
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
final SizedBox sizedBox = tester.widget<SizedBox>(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
expect(sizedBox.width, 360.0);
|
||||
expect(sizedBox.height, 400.0);
|
||||
final Size size = tester.getSize(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(size.width, 360.0);
|
||||
expect(size.height, 400.0);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1234,9 +1234,9 @@ void main() {
|
||||
await tester.pumpWidget(buildSearchAnchor(platform));
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
final SizedBox sizedBox = tester.widget<SizedBox>(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
expect(sizedBox.width, 800.0);
|
||||
expect(sizedBox.height, 600.0);
|
||||
final Size size = tester.getSize(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(size.width, 800.0);
|
||||
expect(size.height, 600.0);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1378,7 +1378,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(Container());
|
||||
await tester.pumpWidget(buildAnchor(viewBuilder: (Iterable<Widget> suggestions)
|
||||
=> GridView.count(crossAxisCount: 5, children: suggestions.toList(),)
|
||||
=> GridView.count(crossAxisCount: 5, children: suggestions.toList())
|
||||
));
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
@@ -1386,6 +1386,36 @@ void main() {
|
||||
expect(find.byType(GridView), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('SearchAnchor.bar respects viewBuilder property', (WidgetTester tester) async {
|
||||
Widget buildAnchor({ViewBuilder? viewBuilder}) {
|
||||
return MaterialApp(
|
||||
home: Material(
|
||||
child: SearchAnchor.bar(
|
||||
viewBuilder: viewBuilder,
|
||||
suggestionsBuilder: (BuildContext context, SearchController controller) {
|
||||
return <Widget>[];
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildAnchor());
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
// Default is a ListView.
|
||||
expect(find.byType(ListView), findsOneWidget);
|
||||
|
||||
await tester.pumpWidget(Container());
|
||||
await tester.pumpWidget(buildAnchor(viewBuilder: (Iterable<Widget> suggestions)
|
||||
=> GridView.count(crossAxisCount: 5, children: suggestions.toList())
|
||||
));
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(ListView), findsNothing);
|
||||
expect(find.byType(GridView), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('SearchAnchor respects viewLeading property', (WidgetTester tester) async {
|
||||
Widget buildAnchor({Widget? viewLeading}) {
|
||||
return MaterialApp(
|
||||
@@ -1692,6 +1722,49 @@ void main() {
|
||||
expect(padding.padding, EdgeInsets.zero);
|
||||
});
|
||||
|
||||
testWidgets('SearchAnchor respects shrinkWrap property', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Material(
|
||||
child: SearchAnchor(
|
||||
isFullScreen: false,
|
||||
shrinkWrap: true,
|
||||
viewConstraints: const BoxConstraints(),
|
||||
builder: (BuildContext context, SearchController controller) {
|
||||
return IconButton(icon: const Icon(Icons.search), onPressed: () {
|
||||
controller.openView();
|
||||
},);
|
||||
},
|
||||
suggestionsBuilder: (BuildContext context, SearchController controller) {
|
||||
return List<Widget>.generate(
|
||||
controller.text.length,
|
||||
(int index) => ListTile(title: Text('Item $index')),
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Finder findDivider = find.descendant(of: findViewContent(), matching: find.byType(Divider));
|
||||
|
||||
// Divider should not be shown if there are no suggestions
|
||||
expect(findDivider, findsNothing);
|
||||
|
||||
final Finder findMaterial = find.descendant(of: findViewContent(), matching: find.byType(Material)).first;
|
||||
final Rect materialRectWithoutSuggestions = tester.getRect(findMaterial);
|
||||
expect(materialRectWithoutSuggestions, equals(const Rect.fromLTRB(0.0, 0.0, 800.0, 56.0)));
|
||||
|
||||
await tester.enterText(find.byType(SearchBar), 'a');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(findDivider, findsOneWidget);
|
||||
|
||||
final Rect materialRectWithSuggestions = tester.getRect(findMaterial);
|
||||
expect(materialRectWithSuggestions, equals(const Rect.fromLTRB(0.0, 0.0, 800.0, 113.0)));
|
||||
});
|
||||
|
||||
testWidgets('SearchAnchor respects dividerColor property', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Material(
|
||||
@@ -1741,9 +1814,9 @@ void main() {
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final SizedBox sizedBox = tester.widget<SizedBox>(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
expect(sizedBox.width, 280.0);
|
||||
expect(sizedBox.height, 390.0);
|
||||
final Size size = tester.getSize(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(size.width, 280.0);
|
||||
expect(size.height, 390.0);
|
||||
});
|
||||
|
||||
testWidgets('SearchAnchor respects viewBarPadding property', (WidgetTester tester) async {
|
||||
@@ -1802,7 +1875,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect, equals(const Rect.fromLTRB(388.0, 0.0, 748.0, 400.0)));
|
||||
|
||||
// Search view top left should be the same as the anchor top left
|
||||
@@ -1839,7 +1912,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect, equals(const Rect.fromLTRB(52.0, 0.0, 412.0, 400.0)));
|
||||
|
||||
// Search view top right should be the same as the anchor top right
|
||||
@@ -2049,7 +2122,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect, equals(const Rect.fromLTRB(0.0, 0.0, 800.0, 400.0)));
|
||||
|
||||
// Search view has same width with the default anchor(search bar).
|
||||
@@ -2128,7 +2201,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect, equals(const Rect.fromLTRB(440.0, 200.0, 800.0, 600.0)));
|
||||
});
|
||||
|
||||
@@ -2169,7 +2242,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect, equals(const Rect.fromLTRB(0.0, 200.0, 360.0, 600.0)));
|
||||
});
|
||||
|
||||
@@ -2216,7 +2289,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect, equals(const Rect.fromLTRB(0.0, 0.0, 200.0, 200.0)));
|
||||
|
||||
// Test RTL text direction.
|
||||
@@ -2231,7 +2304,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRectRTL = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRectRTL = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRectRTL, equals(const Rect.fromLTRB(0.0, 0.0, 200.0, 200.0)));
|
||||
});
|
||||
|
||||
@@ -2394,7 +2467,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect.topLeft, equals(const Offset(rootSpacing, rootSpacing)));
|
||||
});
|
||||
|
||||
@@ -2440,7 +2513,7 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
final Rect searchViewRect = tester.getRect(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(searchViewRect.bottomRight, equals(const Offset(300.0, 300.0)));
|
||||
});
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ void main() {
|
||||
expect(themeData.headerHintStyle, null);
|
||||
expect(themeData.padding, null);
|
||||
expect(themeData.barPadding, null);
|
||||
expect(themeData.shrinkWrap, null);
|
||||
expect(themeData.dividerColor, null);
|
||||
|
||||
const SearchViewTheme theme = SearchViewTheme(data: SearchViewThemeData(), child: SizedBox());
|
||||
@@ -47,6 +48,7 @@ void main() {
|
||||
expect(theme.data.headerHintStyle, null);
|
||||
expect(themeData.padding, null);
|
||||
expect(themeData.barPadding, null);
|
||||
expect(themeData.shrinkWrap, null);
|
||||
expect(theme.data.dividerColor, null);
|
||||
});
|
||||
|
||||
@@ -77,6 +79,7 @@ void main() {
|
||||
constraints: BoxConstraints(minWidth: 350, minHeight: 240),
|
||||
padding: EdgeInsets.only(bottom: 32.0),
|
||||
barPadding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
@@ -95,6 +98,7 @@ void main() {
|
||||
expect(description[8], 'constraints: BoxConstraints(350.0<=w<=Infinity, 240.0<=h<=Infinity)');
|
||||
expect(description[9], 'padding: EdgeInsets(0.0, 0.0, 0.0, 32.0)');
|
||||
expect(description[10], 'barPadding: EdgeInsets.zero');
|
||||
expect(description[11], 'shrinkWrap: true');
|
||||
});
|
||||
|
||||
group('[Theme, SearchViewTheme, SearchView properties overrides]', () {
|
||||
@@ -196,9 +200,9 @@ void main() {
|
||||
expect(material.surfaceTintColor, surfaceTintColor);
|
||||
expect(material.shape, shape);
|
||||
|
||||
final SizedBox sizedBox = tester.widget<SizedBox>(find.descendant(of: findViewContent(), matching: find.byType(SizedBox)).first);
|
||||
expect(sizedBox.width, 250.0);
|
||||
expect(sizedBox.height, 450.0);
|
||||
final Size size = tester.getSize(find.descendant(of: findViewContent(), matching: find.byType(ConstrainedBox)).first);
|
||||
expect(size.width, 250.0);
|
||||
expect(size.height, 450.0);
|
||||
|
||||
final Text hintText = tester.widget(find.text('hint text'));
|
||||
expect(hintText.style?.color, headerHintStyle.color);
|
||||
|
||||
Reference in New Issue
Block a user