Unverified Commit e281c391 authored by Gianluca Bettega's avatar Gianluca Bettega Committed by GitHub

Expose 'enable' property to allow the user to disable the SearchBar (#137388)

This exposes the `enabled` property of the `TextField` widget to the `Searchbar` widget.

## Related Issues

https://github.com/flutter/flutter/issues/136943

Still missing tests
parent 35903620
...@@ -35,6 +35,7 @@ const Curve _kViewFadeOnInterval = Interval(0.0, 1/2); ...@@ -35,6 +35,7 @@ const Curve _kViewFadeOnInterval = Interval(0.0, 1/2);
const Curve _kViewIconsFadeOnInterval = Interval(1/6, 2/6); const Curve _kViewIconsFadeOnInterval = Interval(1/6, 2/6);
const Curve _kViewDividerFadeOnInterval = Interval(0.0, 1/6); const Curve _kViewDividerFadeOnInterval = Interval(0.0, 1/6);
const Curve _kViewListFadeOnInterval = Interval(133 / _kOpenViewMilliseconds, 233 / _kOpenViewMilliseconds); const Curve _kViewListFadeOnInterval = Interval(133 / _kOpenViewMilliseconds, 233 / _kOpenViewMilliseconds);
const double _kDisableSearchBarOpacity = 0.38;
/// Signature for a function that creates a [Widget] which is used to open a search view. /// Signature for a function that creates a [Widget] which is used to open a search view.
/// ///
...@@ -1115,6 +1116,7 @@ class SearchBar extends StatefulWidget { ...@@ -1115,6 +1116,7 @@ class SearchBar extends StatefulWidget {
this.textStyle, this.textStyle,
this.hintStyle, this.hintStyle,
this.textCapitalization, this.textCapitalization,
this.enabled = true,
this.autoFocus = false, this.autoFocus = false,
this.textInputAction, this.textInputAction,
this.keyboardType, this.keyboardType,
...@@ -1239,6 +1241,9 @@ class SearchBar extends StatefulWidget { ...@@ -1239,6 +1241,9 @@ class SearchBar extends StatefulWidget {
/// {@macro flutter.widgets.editableText.textCapitalization} /// {@macro flutter.widgets.editableText.textCapitalization}
final TextCapitalization? textCapitalization; final TextCapitalization? textCapitalization;
/// If false the text field is "disabled" so the SearchBar will ignore taps.
final bool enabled;
/// {@macro flutter.widgets.editableText.autofocus} /// {@macro flutter.widgets.editableText.autofocus}
final bool autoFocus; final bool autoFocus;
...@@ -1340,62 +1345,69 @@ class _SearchBarState extends State<SearchBar> { ...@@ -1340,62 +1345,69 @@ class _SearchBarState extends State<SearchBar> {
return ConstrainedBox( return ConstrainedBox(
constraints: widget.constraints ?? searchBarTheme.constraints ?? defaults.constraints!, constraints: widget.constraints ?? searchBarTheme.constraints ?? defaults.constraints!,
child: Material( child: Opacity(
elevation: effectiveElevation!, opacity: widget.enabled ? 1 : _kDisableSearchBarOpacity,
shadowColor: effectiveShadowColor, child: Material(
color: effectiveBackgroundColor, elevation: effectiveElevation!,
surfaceTintColor: effectiveSurfaceTintColor, shadowColor: effectiveShadowColor,
shape: effectiveShape?.copyWith(side: effectiveSide), color: effectiveBackgroundColor,
child: InkWell( surfaceTintColor: effectiveSurfaceTintColor,
onTap: () { shape: effectiveShape?.copyWith(side: effectiveSide),
widget.onTap?.call(); child: IgnorePointer(
if (!_focusNode.hasFocus) { ignoring: !widget.enabled,
_focusNode.requestFocus(); child: InkWell(
} onTap: () {
}, widget.onTap?.call();
overlayColor: effectiveOverlayColor, if (!_focusNode.hasFocus) {
customBorder: effectiveShape?.copyWith(side: effectiveSide), _focusNode.requestFocus();
statesController: _internalStatesController, }
child: Padding( },
padding: effectivePadding!, overlayColor: effectiveOverlayColor,
child: Row( customBorder: effectiveShape?.copyWith(side: effectiveSide),
textDirection: textDirection, statesController: _internalStatesController,
children: <Widget>[ child: Padding(
if (leading != null) leading, padding: effectivePadding!,
Expanded( child: Row(
child: Padding( textDirection: textDirection,
padding: effectivePadding, children: <Widget>[
child: TextField( if (leading != null) leading,
autofocus: widget.autoFocus, Expanded(
onTap: widget.onTap, child: Padding(
onTapAlwaysCalled: true, padding: effectivePadding,
focusNode: _focusNode, child: TextField(
onChanged: widget.onChanged, autofocus: widget.autoFocus,
onSubmitted: widget.onSubmitted, onTap: widget.onTap,
controller: widget.controller, onTapAlwaysCalled: true,
style: effectiveTextStyle, focusNode: _focusNode,
decoration: InputDecoration( onChanged: widget.onChanged,
hintText: widget.hintText, onSubmitted: widget.onSubmitted,
).applyDefaults(InputDecorationTheme( controller: widget.controller,
hintStyle: effectiveHintStyle, style: effectiveTextStyle,
// The configuration below is to make sure that the text field enabled: widget.enabled,
// in `SearchBar` will not be overridden by the overall `InputDecorationTheme` decoration: InputDecoration(
enabledBorder: InputBorder.none, hintText: widget.hintText,
border: InputBorder.none, ).applyDefaults(InputDecorationTheme(
focusedBorder: InputBorder.none, hintStyle: effectiveHintStyle,
contentPadding: EdgeInsets.zero, // The configuration below is to make sure that the text field
// Setting `isDense` to true to allow the text field height to be // in `SearchBar` will not be overridden by the overall `InputDecorationTheme`
// smaller than 48.0 enabledBorder: InputBorder.none,
isDense: true, border: InputBorder.none,
)), focusedBorder: InputBorder.none,
textCapitalization: effectiveTextCapitalization, contentPadding: EdgeInsets.zero,
textInputAction: widget.textInputAction, // Setting `isDense` to true to allow the text field height to be
keyboardType: widget.keyboardType, // smaller than 48.0
isDense: true,
)),
textCapitalization: effectiveTextCapitalization,
textInputAction: widget.textInputAction,
keyboardType: widget.keyboardType,
),
),
), ),
), if (trailing != null) ...trailing,
],
), ),
if (trailing != null) ...trailing, ),
],
), ),
), ),
), ),
......
...@@ -10,6 +10,8 @@ import 'package:flutter/material.dart'; ...@@ -10,6 +10,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../widgets/semantics_tester.dart';
void main() { void main() {
// Returns the RenderEditable at the given index, or the first if not given. // Returns the RenderEditable at the given index, or the first if not given.
RenderEditable findRenderEditable(WidgetTester tester, {int index = 0}) { RenderEditable findRenderEditable(WidgetTester tester, {int index = 0}) {
...@@ -2945,6 +2947,72 @@ void main() { ...@@ -2945,6 +2947,72 @@ void main() {
final TextField textField = tester.widget(find.byType(TextField)); final TextField textField = tester.widget(find.byType(TextField));
expect(textField.textInputAction, TextInputAction.previous); expect(textField.textInputAction, TextInputAction.previous);
}); });
testWidgets('Block entering text on disabled widget', (WidgetTester tester) async {
const String initValue = 'init';
final TextEditingController controller = TextEditingController(text: initValue);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: SearchBar(
controller: controller,
enabled: false,
),
),
),
),
);
const String testValue = 'abcdefghi';
await tester.enterText(find.byType(SearchBar), testValue);
expect(controller.value.text, initValue);
});
testWidgets('Disabled SearchBar semantics node still contains value', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: SearchBar(
controller: TextEditingController(text: 'text'),
enabled: false,
),
),
),
),
);
expect(semantics, includesNodeWith(actions: <SemanticsAction>[], value: 'text'));
semantics.dispose();
});
testWidgets('Check SearchBar opacity when disabled', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(
child: Center(
child: SearchBar(
enabled: false,
),
),
),
),
);
final Finder searchBarFinder = find.byType(SearchBar);
expect(searchBarFinder, findsOneWidget);
final Finder opacityFinder = find.descendant(
of: searchBarFinder,
matching: find.byType(Opacity),
);
expect(opacityFinder, findsOneWidget);
final Opacity opacityWidget = tester.widget<Opacity>(opacityFinder);
expect(opacityWidget.opacity, 0.38);
});
} }
Future<void> checkSearchBarDefaults(WidgetTester tester, ColorScheme colorScheme, Material material) async { Future<void> checkSearchBarDefaults(WidgetTester tester, ColorScheme colorScheme, Material material) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment