Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
f3947ea0
Unverified
Commit
f3947ea0
authored
4 years ago
by
Justin McCandless
Committed by
GitHub
4 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Autocomplete (Material) (#73753)
* Material Autocomplete widget
parent
d9a69e3b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
542 additions
and
8 deletions
+542
-8
material.dart
packages/flutter/lib/material.dart
+1
-0
autocomplete.dart
packages/flutter/lib/src/material/autocomplete.dart
+253
-0
autocomplete.dart
packages/flutter/lib/src/widgets/autocomplete.dart
+32
-8
autocomplete_test.dart
packages/flutter/test/material/autocomplete_test.dart
+256
-0
No files found.
packages/flutter/lib/material.dart
View file @
f3947ea0
...
...
@@ -22,6 +22,7 @@ export 'src/material/app.dart';
export
'src/material/app_bar.dart'
;
export
'src/material/app_bar_theme.dart'
;
export
'src/material/arc.dart'
;
export
'src/material/autocomplete.dart'
;
export
'src/material/back_button.dart'
;
export
'src/material/banner.dart'
;
export
'src/material/banner_theme.dart'
;
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/material/autocomplete.dart
0 → 100644
View file @
f3947ea0
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/widgets.dart'
;
import
'ink_well.dart'
;
import
'material.dart'
;
import
'text_form_field.dart'
;
/// {@macro flutter.widgets.RawAutocomplete.RawAutocomplete}
///
/// {@tool dartpad --template=freeform}
/// This example shows how to create a very basic Autocomplete widget using the
/// default UI.
///
/// ```dart imports
/// import 'package:flutter/material.dart';
/// ```
///
/// ```dart
/// class AutocompleteBasicExample extends StatelessWidget {
/// AutocompleteBasicExample({Key? key}) : super(key: key);
///
/// final List<String> _kOptions = <String>[
/// 'aardvark',
/// 'bobcat',
/// 'chameleon',
/// ];
///
/// @override
/// Widget build(BuildContext context) {
/// return Autocomplete<String>(
/// optionsBuilder: (TextEditingValue textEditingValue) {
/// if (textEditingValue.text == '') {
/// return const Iterable<String>.empty();
/// }
/// return _kOptions.where((String option) {
/// return option.contains(textEditingValue.text.toLowerCase());
/// });
/// },
/// onSelected: (String selection) {
/// print('You just selected $selection');
/// },
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// {@tool dartpad --template=freeform}
/// This example shows how to create an Autocomplete widget with a custom type.
/// Try searching with text from the name or email field.
///
/// ```dart imports
/// import 'package:flutter/material.dart';
/// ```
///
/// ```dart
/// class User {
/// const User({
/// required this.email,
/// required this.name,
/// });
///
/// final String email;
/// final String name;
///
/// @override
/// String toString() {
/// return '$name, $email';
/// }
///
/// @override
/// bool operator ==(Object other) {
/// if (other.runtimeType != runtimeType)
/// return false;
/// return other is User
/// && other.name == name
/// && other.email == email;
/// }
///
/// @override
/// int get hashCode => hashValues(email, name);
/// }
///
/// class AutocompleteBasicUserExample extends StatelessWidget {
/// AutocompleteBasicUserExample({Key? key}) : super(key: key);
///
/// static final List<User> _userOptions = <User>[
/// User(name: 'Alice', email: 'alice@example.com'),
/// User(name: 'Bob', email: 'bob@example.com'),
/// User(name: 'Charlie', email: 'charlie123@gmail.com'),
/// ];
///
/// static String _displayStringForOption(User option) => option.name;
///
/// @override
/// Widget build(BuildContext context) {
/// return Autocomplete<User>(
/// displayStringForOption: _displayStringForOption,
/// optionsBuilder: (TextEditingValue textEditingValue) {
/// if (textEditingValue.text == '') {
/// return const Iterable<User>.empty();
/// }
/// return _userOptions.where((User option) {
/// return option.toString().contains(textEditingValue.text.toLowerCase());
/// });
/// },
/// onSelected: (User selection) {
/// print('You just selected ${_displayStringForOption(selection)}');
/// },
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [RawAutocomplete], which is what Autocomplete is built upon, and which
/// contains more detailed examples.
class
Autocomplete
<
T
extends
Object
>
extends
StatelessWidget
{
/// Creates an instance of [Autocomplete].
const
Autocomplete
({
Key
?
key
,
required
this
.
optionsBuilder
,
this
.
displayStringForOption
=
RawAutocomplete
.
defaultStringForOption
,
this
.
fieldViewBuilder
=
_defaultFieldViewBuilder
,
this
.
onSelected
,
this
.
optionsViewBuilder
,
})
:
assert
(
displayStringForOption
!=
null
),
assert
(
optionsBuilder
!=
null
),
super
(
key:
key
);
/// {@macro flutter.widgets.RawAutocomplete.displayStringForOption}
final
AutocompleteOptionToString
<
T
>
displayStringForOption
;
/// {@macro flutter.widgets.RawAutocomplete.fieldViewBuilder}
///
/// If not provided, will build a standard Material-style text field by
/// default.
final
AutocompleteFieldViewBuilder
fieldViewBuilder
;
/// {@macro flutter.widgets.RawAutocomplete.onSelected}
final
AutocompleteOnSelected
<
T
>?
onSelected
;
/// {@macro flutter.widgets.RawAutocomplete.optionsBuilder}
final
AutocompleteOptionsBuilder
<
T
>
optionsBuilder
;
/// {@macro flutter.widgets.RawAutocomplete.optionsViewBuilder}
///
/// If not provided, will build a standard Material-style list of results by
/// default.
final
AutocompleteOptionsViewBuilder
<
T
>?
optionsViewBuilder
;
static
Widget
_defaultFieldViewBuilder
(
BuildContext
context
,
TextEditingController
textEditingController
,
FocusNode
focusNode
,
VoidCallback
onFieldSubmitted
)
{
return
_AutocompleteField
(
focusNode:
focusNode
,
textEditingController:
textEditingController
,
onFieldSubmitted:
onFieldSubmitted
,
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
RawAutocomplete
<
T
>(
displayStringForOption:
displayStringForOption
,
fieldViewBuilder:
fieldViewBuilder
,
optionsBuilder:
optionsBuilder
,
optionsViewBuilder:
optionsViewBuilder
??
(
BuildContext
context
,
AutocompleteOnSelected
<
T
>
onSelected
,
Iterable
<
T
>
options
)
{
return
_AutocompleteOptions
<
T
>(
displayStringForOption:
displayStringForOption
,
onSelected:
onSelected
,
options:
options
,
);
},
onSelected:
onSelected
,
);
}
}
// The default Material-style Autocomplete text field.
class
_AutocompleteField
extends
StatelessWidget
{
const
_AutocompleteField
({
Key
?
key
,
required
this
.
focusNode
,
required
this
.
textEditingController
,
required
this
.
onFieldSubmitted
,
})
:
super
(
key:
key
);
final
FocusNode
focusNode
;
final
VoidCallback
onFieldSubmitted
;
final
TextEditingController
textEditingController
;
@override
Widget
build
(
BuildContext
context
)
{
return
TextFormField
(
controller:
textEditingController
,
focusNode:
focusNode
,
onFieldSubmitted:
(
String
value
)
{
onFieldSubmitted
();
},
);
}
}
// The default Material-style Autocomplete options.
class
_AutocompleteOptions
<
T
extends
Object
>
extends
StatelessWidget
{
const
_AutocompleteOptions
({
Key
?
key
,
required
this
.
displayStringForOption
,
required
this
.
onSelected
,
required
this
.
options
,
})
:
super
(
key:
key
);
final
AutocompleteOptionToString
<
T
>
displayStringForOption
;
final
AutocompleteOnSelected
<
T
>
onSelected
;
final
Iterable
<
T
>
options
;
@override
Widget
build
(
BuildContext
context
)
{
return
Align
(
alignment:
Alignment
.
topLeft
,
child:
Material
(
elevation:
4.0
,
child:
Container
(
height:
200.0
,
child:
ListView
.
builder
(
padding:
const
EdgeInsets
.
all
(
0.0
),
itemCount:
options
.
length
,
itemBuilder:
(
BuildContext
context
,
int
index
)
{
final
T
option
=
options
.
elementAt
(
index
);
return
InkWell
(
onTap:
()
{
onSelected
(
option
);
},
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
16.0
),
child:
Text
(
displayStringForOption
(
option
)),
),
);
},
),
),
),
);
}
}
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/autocomplete.dart
View file @
f3947ea0
...
...
@@ -16,6 +16,7 @@ import 'overlay.dart';
/// entered so far.
///
/// See also:
///
/// * [RawAutocomplete.optionsBuilder], which is of this type.
typedef
AutocompleteOptionsBuilder
<
T
extends
Object
>
=
Iterable
<
T
>
Function
(
TextEditingValue
textEditingValue
);
...
...
@@ -23,6 +24,7 @@ typedef AutocompleteOptionsBuilder<T extends Object> = Iterable<T> Function(Text
/// that the user has selected an option.
///
/// See also:
///
/// * [RawAutocomplete.onSelected], which is of this type.
typedef
AutocompleteOnSelected
<
T
extends
Object
>
=
void
Function
(
T
option
);
...
...
@@ -31,6 +33,7 @@ typedef AutocompleteOnSelected<T extends Object> = void Function(T option);
/// selects an option.
///
/// See also:
///
/// * [RawAutocomplete.optionsViewBuilder], which is of this type.
typedef
AutocompleteOptionsViewBuilder
<
T
extends
Object
>
=
Widget
Function
(
BuildContext
context
,
...
...
@@ -42,6 +45,7 @@ typedef AutocompleteOptionsViewBuilder<T extends Object> = Widget Function(
/// contains the input [TextField] or [TextFormField].
///
/// See also:
///
/// * [RawAutocomplete.fieldViewBuilder], which is of this type.
typedef
AutocompleteFieldViewBuilder
=
Widget
Function
(
BuildContext
context
,
...
...
@@ -54,19 +58,21 @@ typedef AutocompleteFieldViewBuilder = Widget Function(
/// a string which can be displayed in the widget's options menu.
///
/// See also:
///
/// * [RawAutocomplete.displayStringForOption], which is of this type.
typedef
AutocompleteOptionToString
<
T
extends
Object
>
=
String
Function
(
T
option
);
// TODO(justinmc): Mention Autocomplete
and AutocompleteCupertino when they are
//
implemented.
// TODO(justinmc): Mention Autocomplete
Cupertino when it is implemented.
//
/ {@template flutter.widgets.RawAutocomplete.RawAutocomplete}
/// A widget for helping the user make a selection by entering some text and
/// choosing from among a list of options.
///
/// This is a core framework widget with very basic UI.
///
/// The user's text input is received in a field built with the
/// [fieldViewBuilder] parameter. The options to be displayed are determined
/// using [optionsBuilder] and rendered with [optionsViewBuilder].
/// {@endtemplate}
///
/// This is a core framework widget with very basic UI.
///
/// {@tool dartpad --template=freeform}
/// This example shows how to create a very basic autocomplete widget using the
...
...
@@ -419,6 +425,11 @@ typedef AutocompleteOptionToString<T extends Object> = String Function(T option)
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Autocomplete], which is a Material-styled implementation that is based
/// on RawAutocomplete.
class
RawAutocomplete
<
T
extends
Object
>
extends
StatefulWidget
{
/// Create an instance of RawAutocomplete.
///
...
...
@@ -428,7 +439,7 @@ class RawAutocomplete<T extends Object> extends StatefulWidget {
Key
?
key
,
required
this
.
optionsViewBuilder
,
required
this
.
optionsBuilder
,
this
.
displayStringForOption
=
_
defaultStringForOption
,
this
.
displayStringForOption
=
defaultStringForOption
,
this
.
fieldViewBuilder
,
this
.
focusNode
,
this
.
onSelected
,
...
...
@@ -444,10 +455,12 @@ class RawAutocomplete<T extends Object> extends StatefulWidget {
assert
((
focusNode
==
null
)
==
(
textEditingController
==
null
)),
super
(
key:
key
);
/// {@template flutter.widgets.RawAutocomplete.fieldViewBuilder}
/// Builds the field whose input is used to get the options.
///
/// Pass the provided [TextEditingController] to the field built here so that
/// RawAutocomplete can listen for changes.
/// {@endtemplate}
final
AutocompleteFieldViewBuilder
?
fieldViewBuilder
;
/// The [FocusNode] that is used for the text field.
...
...
@@ -552,30 +565,38 @@ class RawAutocomplete<T extends Object> extends StatefulWidget {
/// not null.
final
FocusNode
?
focusNode
;
/// {@template flutter.widgets.RawAutocomplete.optionsViewBuilder}
/// Builds the selectable options widgets from a list of options objects.
///
/// The options are displayed floating below the field using a
/// [CompositedTransformFollower] inside of an [Overlay], not at the same
/// place in the widget tree as RawAutocomplete.
/// place in the widget tree as [RawAutocomplete].
/// {@endtemplate}
final
AutocompleteOptionsViewBuilder
<
T
>
optionsViewBuilder
;
/// {@template flutter.widgets.RawAutocomplete.displayStringForOption}
/// Returns the string to display in the field when the option is selected.
///
/// This is useful when using a custom T type and the string to display is
/// different than the string to search by.
///
/// If not provided, will use `option.toString()`.
/// {@endtemplate}
final
AutocompleteOptionToString
<
T
>
displayStringForOption
;
/// {@template flutter.widgets.RawAutocomplete.onSelected}
/// Called when an option is selected by the user.
///
/// Any [TextEditingController] listeners will not be called when the user
/// selects an option, even though the field will update with the selected
/// value, so use this to be informed of selection.
/// {@endtemplate}
final
AutocompleteOnSelected
<
T
>?
onSelected
;
/// {@template flutter.widgets.RawAutocomplete.optionsBuilder}
/// A function that returns the current selectable options objects given the
/// current TextEditingValue.
/// {@endtemplate}
final
AutocompleteOptionsBuilder
<
T
>
optionsBuilder
;
/// The [TextEditingController] that is used for the text field.
...
...
@@ -603,8 +624,11 @@ class RawAutocomplete<T extends Object> extends StatefulWidget {
rawAutocomplete
.
_onFieldSubmitted
();
}
// The default way to convert an option to a string.
static
String
_defaultStringForOption
(
dynamic
option
)
{
/// The default way to convert an option to a string in
/// [displayStringForOption].
///
/// Simply uses the `toString` method on the option.
static
String
defaultStringForOption
(
dynamic
option
)
{
return
option
.
toString
();
}
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/autocomplete_test.dart
0 → 100644
View file @
f3947ea0
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
class
User
{
const
User
({
required
this
.
email
,
required
this
.
name
,
});
final
String
email
;
final
String
name
;
@override
String
toString
()
{
return
'
$name
,
$email
'
;
}
}
void
main
(
)
{
const
List
<
String
>
kOptions
=
<
String
>[
'aardvark'
,
'bobcat'
,
'chameleon'
,
'dingo'
,
'elephant'
,
'flamingo'
,
'goose'
,
'hippopotamus'
,
'iguana'
,
'jaguar'
,
'koala'
,
'lemur'
,
'mouse'
,
'northern white rhinocerous'
,
];
const
List
<
User
>
kOptionsUsers
=
<
User
>[
User
(
name:
'Alice'
,
email:
'alice@example.com'
),
User
(
name:
'Bob'
,
email:
'bob@example.com'
),
User
(
name:
'Charlie'
,
email:
'charlie123@gmail.com'
),
];
testWidgets
(
'can filter and select a list of string options'
,
(
WidgetTester
tester
)
async
{
late
String
lastSelection
;
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Autocomplete
<
String
>(
onSelected:
(
String
selection
)
{
lastSelection
=
selection
;
},
optionsBuilder:
(
TextEditingValue
textEditingValue
)
{
return
kOptions
.
where
((
String
option
)
{
return
option
.
contains
(
textEditingValue
.
text
.
toLowerCase
());
});
},
),
),
),
);
// The field is always rendered, but the options are not unless needed.
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsNothing
);
// Focus the empty field. All the options are displayed.
await
tester
.
tap
(
find
.
byType
(
TextFormField
));
await
tester
.
pump
();
expect
(
find
.
byType
(
ListView
),
findsOneWidget
);
ListView
list
=
find
.
byType
(
ListView
).
evaluate
().
first
.
widget
as
ListView
;
expect
(
list
.
semanticChildCount
,
kOptions
.
length
);
// Enter text. The options are filtered by the text.
await
tester
.
enterText
(
find
.
byType
(
TextFormField
),
'ele'
);
await
tester
.
pump
();
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsOneWidget
);
list
=
find
.
byType
(
ListView
).
evaluate
().
first
.
widget
as
ListView
;
// 'chameleon' and 'elephant' are displayed.
expect
(
list
.
semanticChildCount
,
2
);
// Select a option. The options hide and the field updates to show the
// selection.
await
tester
.
tap
(
find
.
byType
(
InkWell
).
first
);
await
tester
.
pump
();
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsNothing
);
final
TextFormField
field
=
find
.
byType
(
TextFormField
).
evaluate
().
first
.
widget
as
TextFormField
;
expect
(
field
.
controller
!.
text
,
'chameleon'
);
expect
(
lastSelection
,
'chameleon'
);
// Modify the field text. The options appear again and are filtered.
await
tester
.
enterText
(
find
.
byType
(
TextFormField
),
'e'
);
await
tester
.
pump
();
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsOneWidget
);
list
=
find
.
byType
(
ListView
).
evaluate
().
first
.
widget
as
ListView
;
// 'chameleon', 'elephant', 'goose', 'lemur', 'mouse', and
// 'northern white rhinocerous' are displayed.
expect
(
list
.
semanticChildCount
,
6
);
});
testWidgets
(
'can filter and select a list of custom User options'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Autocomplete
<
User
>(
optionsBuilder:
(
TextEditingValue
textEditingValue
)
{
return
kOptionsUsers
.
where
((
User
option
)
{
return
option
.
toString
().
contains
(
textEditingValue
.
text
.
toLowerCase
());
});
},
),
),
),
);
// The field is always rendered, but the options are not unless needed.
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsNothing
);
// Focus the empty field. All the options are displayed.
await
tester
.
tap
(
find
.
byType
(
TextFormField
));
await
tester
.
pump
();
expect
(
find
.
byType
(
ListView
),
findsOneWidget
);
ListView
list
=
find
.
byType
(
ListView
).
evaluate
().
first
.
widget
as
ListView
;
expect
(
list
.
semanticChildCount
,
kOptionsUsers
.
length
);
// Enter text. The options are filtered by the text.
await
tester
.
enterText
(
find
.
byType
(
TextFormField
),
'example'
);
await
tester
.
pump
();
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsOneWidget
);
list
=
find
.
byType
(
ListView
).
evaluate
().
first
.
widget
as
ListView
;
// 'Alice' and 'Bob' are displayed because they have "example.com" emails.
expect
(
list
.
semanticChildCount
,
2
);
// Select a option. The options hide and the field updates to show the
// selection.
await
tester
.
tap
(
find
.
byType
(
InkWell
).
first
);
await
tester
.
pump
();
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsNothing
);
final
TextFormField
field
=
find
.
byType
(
TextFormField
).
evaluate
().
first
.
widget
as
TextFormField
;
expect
(
field
.
controller
!.
text
,
'Alice, alice@example.com'
);
// Modify the field text. The options appear again and are filtered.
await
tester
.
enterText
(
find
.
byType
(
TextFormField
),
'B'
);
await
tester
.
pump
();
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsOneWidget
);
list
=
find
.
byType
(
ListView
).
evaluate
().
first
.
widget
as
ListView
;
// 'Bob' is displayed.
expect
(
list
.
semanticChildCount
,
1
);
});
testWidgets
(
'displayStringForOption is displayed in the options'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Autocomplete
<
User
>(
displayStringForOption:
(
User
option
)
{
return
option
.
name
;
},
optionsBuilder:
(
TextEditingValue
textEditingValue
)
{
return
kOptionsUsers
.
where
((
User
option
)
{
return
option
.
toString
().
contains
(
textEditingValue
.
text
.
toLowerCase
());
});
},
),
),
),
);
// The field is always rendered, but the options are not unless needed.
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsNothing
);
// Focus the empty field. All the options are displayed, and the string that
// is used comes from displayStringForOption.
await
tester
.
tap
(
find
.
byType
(
TextFormField
));
await
tester
.
pump
();
expect
(
find
.
byType
(
ListView
),
findsOneWidget
);
final
ListView
list
=
find
.
byType
(
ListView
).
evaluate
().
first
.
widget
as
ListView
;
expect
(
list
.
semanticChildCount
,
kOptionsUsers
.
length
);
for
(
int
i
=
0
;
i
<
kOptionsUsers
.
length
;
i
++)
{
expect
(
find
.
text
(
kOptionsUsers
[
i
].
name
),
findsOneWidget
);
}
// Select a option. The options hide and the field updates to show the
// selection. The text in the field is given by displayStringForOption.
await
tester
.
tap
(
find
.
byType
(
InkWell
).
first
);
await
tester
.
pump
();
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
expect
(
find
.
byType
(
ListView
),
findsNothing
);
final
TextFormField
field
=
find
.
byType
(
TextFormField
).
evaluate
().
first
.
widget
as
TextFormField
;
expect
(
field
.
controller
!.
text
,
kOptionsUsers
.
first
.
name
);
});
testWidgets
(
'can build a custom field'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
fieldKey
=
GlobalKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Autocomplete
<
String
>(
optionsBuilder:
(
TextEditingValue
textEditingValue
)
{
return
kOptions
.
where
((
String
option
)
{
return
option
.
contains
(
textEditingValue
.
text
.
toLowerCase
());
});
},
fieldViewBuilder:
(
BuildContext
context
,
TextEditingController
textEditingController
,
FocusNode
focusNode
,
VoidCallback
onFieldSubmitted
)
{
return
Container
(
key:
fieldKey
);
},
),
),
),
);
// The custom field is rendered and not the default TextFormField.
expect
(
find
.
byKey
(
fieldKey
),
findsOneWidget
);
expect
(
find
.
byType
(
TextFormField
),
findsNothing
);
});
testWidgets
(
'can build custom options'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
optionsKey
=
GlobalKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Autocomplete
<
String
>(
optionsBuilder:
(
TextEditingValue
textEditingValue
)
{
return
kOptions
.
where
((
String
option
)
{
return
option
.
contains
(
textEditingValue
.
text
.
toLowerCase
());
});
},
optionsViewBuilder:
(
BuildContext
context
,
AutocompleteOnSelected
<
String
>
onSelected
,
Iterable
<
String
>
options
)
{
return
Container
(
key:
optionsKey
);
},
),
),
),
);
// The default field is rendered but not the options, yet.
expect
(
find
.
byKey
(
optionsKey
),
findsNothing
);
expect
(
find
.
byType
(
TextFormField
),
findsOneWidget
);
// Focus the empty field. The custom options is displayed.
await
tester
.
tap
(
find
.
byType
(
TextFormField
));
await
tester
.
pump
();
expect
(
find
.
byKey
(
optionsKey
),
findsOneWidget
);
});
}
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment