├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── libraries
│ ├── Dart_Packages.xml
│ ├── Dart_SDK.xml
│ └── Flutter_Plugins.xml
├── misc.xml
├── modules.xml
└── workspace.xml
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android
└── app
│ └── src
│ └── main
│ └── java
│ └── io
│ └── flutter
│ └── plugins
│ └── GeneratedPluginRegistrant.java
├── auto_complete_text_view.iml
├── lib
└── auto_complete_text_view.dart
├── pubspec.lock
├── pubspec.yaml
├── res
└── values
│ └── strings_en.arb
└── test
└── auto_complete_text_view_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 | ios/.generated/
9 | ios/Flutter/Generated.xcconfig
10 | ios/Runner/GeneratedPluginRegistrant.*
11 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_Packages.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/libraries/Flutter_Plugins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | bloc
49 | bloc.
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | 1553539733700
163 |
164 |
165 | 1553539733700
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713
8 | channel: stable
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [0.0.1] - TODO: Add release date.
2 |
3 | * TODO: Describe initial release.
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | TODO: Add your license here.
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # auto_complete_text_view
2 |
3 | A simple yet customizable autoCompleteTextField for flutter
4 |
5 | ## Example Code
6 | ```
7 | getSuggestionsListFunction :
8 |
9 | Future> getLocationSuggestionsList(String locationText) async {
10 | final bloc = BlocProvider.of(context);
11 | List suggestionList = List();
12 | LocationModel data = await bloc.fetchLocationSuggestions(locationText);
13 | if (data != null) {
14 | for (Predictions predictions in data.predictions) {
15 | suggestionsKeyValuePairs[predictions.description] = predictions.placeId;
16 | if (!suggestionList.contains(predictions.description))
17 | suggestionList.add(predictions.description);
18 | }
19 | return suggestionList;
20 | } else {
21 | return [''];
22 | }
23 | }
24 |
25 |
26 |
27 | function declaration :
28 | AutoCompleteTextView(
29 | suggestionsApiFetchDelay: 300,
30 | focusGained: () {},
31 | onTapCallback: (_) async {
32 | locationSavedStatus = LocationSaveStatus.inProgress;
33 | saveLocationValuesFromGeoCoding(bloc).then(
34 | (_) =>
35 | locationSavedStatus = LocationSaveStatus.saved,
36 | );
37 | },
38 | focusLost: () {
39 | locationSavedStatus = LocationSaveStatus.saved;
40 | if (locationTextController.text.isEmpty) {
41 | city = '';
42 | state = '';
43 | country = '';
44 | locationTextController.text = '';
45 | } else {
46 | locationTextController.text = getLocationString(
47 | country: country, state: state, city: city);
48 | }
49 | },
50 | onValueChanged: (String text) {
51 | locationSavedStatus = text.isNotEmpty
52 | ? (getLocationString(
53 | city: '', state: '', country: '')
54 | .trim() ==
55 | text.trim())
56 | ? LocationSaveStatus.saved
57 | : LocationSaveStatus.notSaved
58 | : LocationSaveStatus.saved;
59 | },
60 | controller: locationTextController,
61 | suggestionStyle: Theme.of(context).textTheme.body1,
62 | getSuggestionsMethod: getLocationSuggestionsList,
63 | tfTextAlign: TextAlign.left,
64 | tfStyle: TextStyle(
65 | fontSize: 16,
66 | color: Theme.of(context).textTheme.body1.color,
67 | ),
68 | tfTextDecoration: InputDecoration(
69 | border: InputBorder.none,
70 | hintText: msgLocationHint1,
71 | ),
72 | ),
73 | ```
74 |
--------------------------------------------------------------------------------
/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java:
--------------------------------------------------------------------------------
1 | package io.flutter.plugins;
2 |
3 | import io.flutter.plugin.common.PluginRegistry;
4 |
5 | /**
6 | * Generated file. Do not edit.
7 | */
8 | public final class GeneratedPluginRegistrant {
9 | public static void registerWith(PluginRegistry registry) {
10 | if (alreadyRegisteredWith(registry)) {
11 | return;
12 | }
13 | }
14 |
15 | private static boolean alreadyRegisteredWith(PluginRegistry registry) {
16 | final String key = GeneratedPluginRegistrant.class.getCanonicalName();
17 | if (registry.hasPlugin(key)) {
18 | return true;
19 | }
20 | registry.registrarFor(key);
21 | return false;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/auto_complete_text_view.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/auto_complete_text_view.dart:
--------------------------------------------------------------------------------
1 | library auto_complete_text_view;
2 |
3 | import 'dart:async';
4 |
5 | import 'package:flutter/material.dart';
6 | import 'package:rxdart/rxdart.dart';
7 |
8 | typedef void OnTapCallback(String value);
9 |
10 | class AutoCompleteTextView extends StatefulWidget
11 | with AutoCompleteTextInterface {
12 | final double maxHeight;
13 | final TextEditingController controller;
14 |
15 | //AutoCompleteTextField properties
16 | final tfCursorColor;
17 | final tfCursorWidth;
18 | final tfStyle;
19 | final tfTextDecoration;
20 | final tfTextAlign;
21 | //Suggestiondrop Down properties
22 | final suggestionStyle;
23 | final suggestionTextAlign;
24 | final onTapCallback;
25 | final Function getSuggestionsMethod;
26 | final Function focusGained;
27 | final Function focusLost;
28 | final int suggestionsApiFetchDelay;
29 | final Function onValueChanged;
30 |
31 | AutoCompleteTextView(
32 | {@required this.controller,
33 | this.onTapCallback,
34 | this.maxHeight = 200,
35 | this.tfCursorColor = Colors.white,
36 | this.tfCursorWidth = 2.0,
37 | this.tfStyle = const TextStyle(color: Colors.black),
38 | this.tfTextDecoration = const InputDecoration(),
39 | this.tfTextAlign = TextAlign.left,
40 | this.suggestionStyle = const TextStyle(color: Colors.black),
41 | this.suggestionTextAlign = TextAlign.left,
42 | @required this.getSuggestionsMethod,
43 | this.focusGained,
44 | this.suggestionsApiFetchDelay = 0,
45 | this.focusLost,
46 | this.onValueChanged});
47 | @override
48 | _AutoCompleteTextViewState createState() => _AutoCompleteTextViewState();
49 |
50 | //This funciton is called when a user clicks on a suggestion
51 | @override
52 | void onTappedSuggestion(String suggestion) {
53 | onTapCallback(suggestion);
54 | }
55 | }
56 |
57 | class _AutoCompleteTextViewState extends State {
58 | ScrollController scrollController = ScrollController();
59 | FocusNode _focusNode = FocusNode();
60 | OverlayEntry _overlayEntry;
61 | LayerLink _layerLink = LayerLink();
62 | final suggestionsStreamController = new BehaviorSubject>();
63 | List suggestionShowList = List();
64 | Timer _debounce;
65 | bool isSearching = true;
66 | @override
67 | void initState() {
68 | super.initState();
69 | _focusNode.addListener(() {
70 | if (_focusNode.hasFocus) {
71 | this._overlayEntry = this._createOverlayEntry();
72 | Overlay.of(context).insert(this._overlayEntry);
73 | (widget.focusGained != null) ? widget.focusGained() : () {};
74 | } else {
75 | this._overlayEntry.remove();
76 | (widget.focusLost != null) ? widget.focusLost() : () {};
77 | }
78 | });
79 | widget.controller.addListener(_onSearchChanged);
80 | }
81 |
82 | _onSearchChanged() {
83 | if (_debounce?.isActive ?? false) _debounce.cancel();
84 | _debounce =
85 | Timer(Duration(milliseconds: widget.suggestionsApiFetchDelay), () {
86 | if (isSearching == true) {
87 | _getSuggestions(widget.controller.text);
88 | }
89 | });
90 | }
91 |
92 | _getSuggestions(String data) async {
93 | if (data.length > 0 && data != null) {
94 | List list = await widget.getSuggestionsMethod(data);
95 | suggestionsStreamController.sink.add(list);
96 | }
97 | }
98 |
99 | OverlayEntry _createOverlayEntry() {
100 | RenderBox renderBox = context.findRenderObject();
101 | var size = renderBox.size;
102 | return OverlayEntry(
103 | builder: (context) => Positioned(
104 | width: size.width,
105 | child: CompositedTransformFollower(
106 | link: this._layerLink,
107 | showWhenUnlinked: false,
108 | offset: Offset(0.0, size.height + 5.0),
109 | child: Material(
110 | elevation: 4.0,
111 | child: StreamBuilder