Giter Site home page Giter Site logo

Comments (11)

sirapolw avatar sirapolw commented on May 29, 2024 4

`import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:math';

typedef Widget AutoCompleteOverlayItemBuilder(
BuildContext context, T suggestion);

typedef bool Filter(T suggestion, String query);

typedef InputEventCallback(T data);

typedef StringCallback(String data);

class AutoCompleteTextField extends StatefulWidget {
final List suggestions;
final Filter itemFilter;
final Comparator itemSorter;
final StringCallback textChanged, textSubmitted;
final ValueSetter onFocusChanged;
final InputEventCallback itemSubmitted;
final AutoCompleteOverlayItemBuilder itemBuilder;
final GlobalKey<AutoCompleteTextFieldState> key;
final bool submitOnSuggestionTap, clearOnSubmit;
final List inputFormatters;
final int minLength;

final InputDecoration decoration;
final TextStyle style;
final TextInputType keyboardType;
final TextInputAction textInputAction;
final TextCapitalization textCapitalization;
final TextEditingController controller;
final FocusNode focusNode;

AutoCompleteTextField(
{@required
this.itemSubmitted, //Callback on item selected, this is the item selected of type
@required
this.key, //GlobalKey used to enable addSuggestion etc
@required
this.suggestions, //Suggestions that will be displayed
@required
this.itemBuilder, //Callback to build each item, return a Widget
@required
this.itemSorter, //Callback to sort items in the form (a of type , b of type )
@required
this.itemFilter, //Callback to filter item: return true or false depending on input text
this.inputFormatters,
this.style,
this.decoration: const InputDecoration(),
this.textChanged, //Callback on input text changed, this is a string
this.textSubmitted, //Callback on input text submitted, this is also a string
this.onFocusChanged,
this.keyboardType: TextInputType.text,
// this.suggestionsAmount:
// 5, //The amount of suggestions to show, larger values may result in them going off screen
this.submitOnSuggestionTap:
true, //Call textSubmitted on suggestion tap, itemSubmitted will be called no matter what
this.clearOnSubmit: true, //Clear autoCompleteTextfield on submit
this.textInputAction: TextInputAction.done,
this.textCapitalization: TextCapitalization.sentences,
this.minLength = 1,
this.controller,
this.focusNode})
: super(key: key);

void clear() => key.currentState.clear();

void addSuggestion(T suggestion) =>
key.currentState.addSuggestion(suggestion);

void removeSuggestion(T suggestion) =>
key.currentState.removeSuggestion(suggestion);

void updateSuggestions(List suggestions) =>
key.currentState.updateSuggestions(suggestions);

void triggerSubmitted() => key.currentState.triggerSubmitted();

void updateDecoration(
{InputDecoration decoration,
List inputFormatters,
TextCapitalization textCapitalization,
TextStyle style,
TextInputType keyboardType,
TextInputAction textInputAction}) =>
key.currentState.updateDecoration(decoration, inputFormatters,
textCapitalization, style, keyboardType, textInputAction);

TextField get textField => key.currentState.textField;

@OverRide
State createState() => new AutoCompleteTextFieldState(
suggestions,
textChanged,
textSubmitted,
onFocusChanged,
itemSubmitted,
itemBuilder,
itemSorter,
itemFilter,
submitOnSuggestionTap,
clearOnSubmit,
minLength,
inputFormatters,
textCapitalization,
decoration,
style,
keyboardType,
textInputAction,
controller,
focusNode);
}

class AutoCompleteTextFieldState extends State {
final LayerLink _layerLink = LayerLink();

TextField textField;
List suggestions;
StringCallback textChanged, textSubmitted;
ValueSetter onFocusChanged;
InputEventCallback itemSubmitted;
AutoCompleteOverlayItemBuilder itemBuilder;
Comparator itemSorter;
OverlayEntry listSuggestionsEntry;
List filteredSuggestions;
Filter itemFilter;
int minLength;
bool submitOnSuggestionTap, clearOnSubmit;
TextEditingController controller;
FocusNode focusNode;

String currentText = "";

InputDecoration decoration;
List inputFormatters;
TextCapitalization textCapitalization;
TextStyle style;
TextInputType keyboardType;
TextInputAction textInputAction;

AutoCompleteTextFieldState(
this.suggestions,
this.textChanged,
this.textSubmitted,
this.onFocusChanged,
this.itemSubmitted,
this.itemBuilder,
this.itemSorter,
this.itemFilter,
this.submitOnSuggestionTap,
this.clearOnSubmit,
this.minLength,
this.inputFormatters,
this.textCapitalization,
this.decoration,
this.style,
this.keyboardType,
this.textInputAction,
this.controller,
this.focusNode) {
textField = new TextField(
inputFormatters: inputFormatters,
textCapitalization: textCapitalization,
decoration: decoration,
style: style,
keyboardType: keyboardType,
focusNode: focusNode ?? new FocusNode(),
controller: controller ?? new TextEditingController(),
textInputAction: textInputAction,
onChanged: (newText) {
currentText = newText;
updateOverlay(newText);

    if (textChanged != null) {
      textChanged(newText);
    }
  },
  onTap: () {
    updateOverlay(currentText);
  },
  onSubmitted: (submittedText) =>
      triggerSubmitted(submittedText: submittedText),
);

if (this.controller != null && this.controller.text != null) {
  currentText = this.controller.text;
}

textField.focusNode.addListener(() {
  if (onFocusChanged != null) {
    onFocusChanged(textField.focusNode.hasFocus);
  }

  if (!textField.focusNode.hasFocus) {
    filteredSuggestions = [];
    updateOverlay();
  } else if (!(currentText == "" || currentText == null)) {
    updateOverlay(currentText);
  }
});

}

void updateDecoration(
InputDecoration decoration,
List inputFormatters,
TextCapitalization textCapitalization,
TextStyle style,
TextInputType keyboardType,
TextInputAction textInputAction) {
if (decoration != null) {
this.decoration = decoration;
}

if (inputFormatters != null) {
  this.inputFormatters = inputFormatters;
}

if (textCapitalization != null) {
  this.textCapitalization = textCapitalization;
}

if (style != null) {
  this.style = style;
}

if (keyboardType != null) {
  this.keyboardType = keyboardType;
}

if (textInputAction != null) {
  this.textInputAction = textInputAction;
}

setState(() {
  textField = new TextField(
    inputFormatters: this.inputFormatters,
    textCapitalization: this.textCapitalization,
    decoration: this.decoration,
    style: this.style,
    keyboardType: this.keyboardType,
    focusNode: focusNode ?? new FocusNode(),
    controller: controller ?? new TextEditingController(),
    textInputAction: this.textInputAction,
    onChanged: (newText) {
      currentText = newText;
      updateOverlay(newText);

      if (textChanged != null) {
        textChanged(newText);
      }
    },
    onTap: () {
      updateOverlay(currentText);
    },
    onSubmitted: (submittedText) =>
        triggerSubmitted(submittedText: submittedText),
  );
});

}

void triggerSubmitted({submittedText}) {
submittedText == null
? textSubmitted(currentText)
: textSubmitted(submittedText);

if (clearOnSubmit) {
  clear();
}

}

void clear() {
textField.controller.clear();
currentText = "";
updateOverlay();
}

void addSuggestion(T suggestion) {
suggestions.add(suggestion);
updateOverlay(currentText);
}

void removeSuggestion(T suggestion) {
suggestions.contains(suggestion)
? suggestions.remove(suggestion)
: throw "List does not contain suggestion and therefore cannot be removed";
updateOverlay(currentText);
}

void updateSuggestions(List suggestions) {
this.suggestions = suggestions;
updateOverlay(currentText);
}

void updateOverlay([String query]) {
if (listSuggestionsEntry == null) {
final Size textFieldSize = (context.findRenderObject() as RenderBox).size;
final width = textFieldSize.width;
final height = textFieldSize.height;
listSuggestionsEntry = new OverlayEntry(builder: (context) {
return new Positioned(
width: width,
child: CompositedTransformFollower(
link: _layerLink,
showWhenUnlinked: false,
offset: Offset(0.0, height),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: width,
minHeight: 0,
maxHeight: max(
0,
MediaQuery.of(context).viewInsets.bottom -
height -
15),
),
child: new Card(
child: Scrollbar(
child: SingleChildScrollView(
child: new Column(
children: filteredSuggestions.map((suggestion) {
return new InkWell(
child: itemBuilder(context, suggestion),
onTap: () {
setState(() {
if (submitOnSuggestionTap) {
String Text = suggestion.toString();
textField.controller.text = Text;
textField.focusNode.unfocus();
itemSubmitted(suggestion);
if (clearOnSubmit) {
clear();
}
} else {
String Text = suggestion.toString();
textField.controller.text = Text;
textChanged(Text);
}
});
});
}).toList(),
),
),
)))));
});
Overlay.of(context).insert(listSuggestionsEntry);
}

filteredSuggestions = getSuggestions(
    suggestions,
    itemSorter,
    itemFilter,
    // suggestionsAmount,
    query);

listSuggestionsEntry.markNeedsBuild();

}

List getSuggestions(
List suggestions,
Comparator sorter,
Filter filter,
String query) {
if (null == query || query.length < minLength) {
return [];
}

suggestions = suggestions.where((item) => filter(item, query)).toList();
suggestions.sort(sorter);
return suggestions;

}

@OverRide
void dispose() {
// if we created our own focus node and controller, dispose of them
// otherwise, let the caller dispose of their own instances
if (focusNode == null) {
textField.focusNode.dispose();
}
if (controller == null) {
textField.controller.dispose();
}
super.dispose();
}

@OverRide
Widget build(BuildContext context) {
return CompositedTransformTarget(link: _layerLink, child: textField);
}
}

class SimpleAutoCompleteTextField extends AutoCompleteTextField {
final StringCallback textChanged, textSubmitted;
final int minLength;
final ValueSetter onFocusChanged;
final TextEditingController controller;
final FocusNode focusNode;

SimpleAutoCompleteTextField(
{TextStyle style,
InputDecoration decoration: const InputDecoration(),
this.onFocusChanged,
this.textChanged,
this.textSubmitted,
this.minLength = 1,
this.controller,
this.focusNode,
TextInputType keyboardType: TextInputType.text,
@required GlobalKey<AutoCompleteTextFieldState> key,
@required List suggestions,
bool submitOnSuggestionTap: true,
bool clearOnSubmit: true,
TextInputAction textInputAction: TextInputAction.done,
TextCapitalization textCapitalization: TextCapitalization.sentences})
: super(
style: style,
decoration: decoration,
textChanged: textChanged,
textSubmitted: textSubmitted,
itemSubmitted: textSubmitted,
keyboardType: keyboardType,
key: key,
suggestions: suggestions,
itemBuilder: null,
itemSorter: null,
itemFilter: null,
submitOnSuggestionTap: submitOnSuggestionTap,
clearOnSubmit: clearOnSubmit,
textInputAction: textInputAction,
textCapitalization: textCapitalization);

@OverRide
State createState() => new AutoCompleteTextFieldState(
suggestions,
textChanged,
textSubmitted,
onFocusChanged,
itemSubmitted, (context, item) {
return new Padding(padding: EdgeInsets.all(8.0), child: new Text(item));
}, (a, b) {
return a.compareTo(b);
}, (item, query) {
return item.toLowerCase().startsWith(query.toLowerCase());
},
submitOnSuggestionTap,
clearOnSubmit,
minLength,
[],
textCapitalization,
decoration,
style,
keyboardType,
textInputAction,
controller,
focusNode);
}

`
Here's my working version of autocomplete textfield with scrollable, implemented from @tuarrep 's snippet. thank me later.

from flutter-autocomplete-textfield.

tuarrep avatar tuarrep commented on May 29, 2024 1

Here my quick and dirty, only-for-my-needs snippet.
No time now to make it more configurable and push a PR

listSuggestionsEntry = OverlayEntry(builder: (context) {
    return Positioned(
        width: width,
        child: CompositedTransformFollower(
            link: _layerLink,
            showWhenUnlinked: false,
            offset: Offset(0.0, height),
            child: ConstrainedBox(
                constraints: BoxConstraints(
                    minWidth: width,
                    maxWidth: width,
                    minHeight: 0,
                    maxHeight: max(0,
                        MediaQuery.of(context).viewInsets.bottom - height - 15)),
                child: Card(
                    child: SingleChildScrollView(
                        child: Column(
                  children: filteredSuggestions.map((suggestion) {
                    return Row(children: [
                      Expanded(
                          child: InkWell(
                              child: itemBuilder(context, suggestion),
                              onTap: () {
                                setState(() {
                                  if (submitOnSuggestionTap) {
                                    String Text = suggestion.toString();
                                    textField.controller.text = Text;
                                    textField.focusNode.unfocus();
                                    itemSubmitted(suggestion);
                                    if (clearOnSubmit) {
                                      clear();
                                    }
                                  } else {
                                    String Text = suggestion.toString();
                                    textField.controller.text = Text;
                                    textChanged(Text);
                                  }
                                });
                              }))
                    ]);
                  }).toList(),
                ))))));
}

Hope it helps

from flutter-autocomplete-textfield.

pacakman avatar pacakman commented on May 29, 2024 1

Here my quick and dirty, only-for-my-needs snippet.
No time now to make it more configurable and push a PR

listSuggestionsEntry = OverlayEntry(builder: (context) {
    return Positioned(
        width: width,
        child: CompositedTransformFollower(
            link: _layerLink,
            showWhenUnlinked: false,
            offset: Offset(0.0, height),
            child: ConstrainedBox(
                constraints: BoxConstraints(
                    minWidth: width,
                    maxWidth: width,
                    minHeight: 0,
                    maxHeight: max(0,
                        MediaQuery.of(context).viewInsets.bottom - height - 15)),
                child: Card(
                    child: SingleChildScrollView(
                        child: Column(
                  children: filteredSuggestions.map((suggestion) {
                    return Row(children: [
                      Expanded(
                          child: InkWell(
                              child: itemBuilder(context, suggestion),
                              onTap: () {
                                setState(() {
                                  if (submitOnSuggestionTap) {
                                    String Text = suggestion.toString();
                                    textField.controller.text = Text;
                                    textField.focusNode.unfocus();
                                    itemSubmitted(suggestion);
                                    if (clearOnSubmit) {
                                      clear();
                                    }
                                  } else {
                                    String Text = suggestion.toString();
                                    textField.controller.text = Text;
                                    textChanged(Text);
                                  }
                                });
                              }))
                    ]);
                  }).toList(),
                ))))));
}

Hope it helps

Currently, this is the best way. Thank you

from flutter-autocomplete-textfield.

danieramiz avatar danieramiz commented on May 29, 2024

YES! WE NEED THIS!

from flutter-autocomplete-textfield.

anthonycic avatar anthonycic commented on May 29, 2024

For everyone who's asking the same thing, i find another solution :

SimpleAutocompleteFormField

Check on Google.

from flutter-autocomplete-textfield.

marcelser avatar marcelser commented on May 29, 2024

@tuarrep Tried to use this snippet but it doesn't even pass syntax check. Flutter reports "Too many positional arguments 0 expected but 1 found". It seems the code snippet is incomplete to replace the whole listSuggestionsEntry assignment. Also when trying to collapse in Android Studio it has at least missing brackets. Tried adding those but it didn't help on the positional argument error.

Can you please post a complete example block for filling listSuggestionsEntry

Update: I found the missing part but now I wonder why only 2 entries are shown and why there's now scrollbar

from flutter-autocomplete-textfield.

tuarrep avatar tuarrep commented on May 29, 2024

@marcelser

It works fine on my side. This snippet was extracted from a working and published app (I've added missing bracket).

Without more precise information I can't help you.

from flutter-autocomplete-textfield.

sirapolw avatar sirapolw commented on May 29, 2024

I tried this snippet, turn out the overlay does not show up.

from flutter-autocomplete-textfield.

tuarrep avatar tuarrep commented on May 29, 2024

I'm sorry @sirapolw I couldn't help you. It was working for me in December. Since then the project was shipped to my client and I do not maintain it anymore.

from flutter-autocomplete-textfield.

adschi avatar adschi commented on May 29, 2024

Any updates on this? Really need that feature

from flutter-autocomplete-textfield.

mustafabhatkar avatar mustafabhatkar commented on May 29, 2024

Here is my working snippet If the above shared code is not working for you:

 listSuggestionsEntry = OverlayEntry(builder: (context) {
        return Positioned(
            width: width,
            child: CompositedTransformFollower(
                link: _layerLink,
                showWhenUnlinked: false,
                offset: Offset(0.0, height),
                child: SizedBox(
                    width: width,
                    height: 300,
                    child: SingleChildScrollView(
                      child: Card(
                          child:  Column(
                        children: filteredSuggestions!.map((suggestion) {
                          return Row(children: [
                            Expanded(
                                child: InkWell(
                                    child: itemBuilder!(context, suggestion),
                                    onTap: () {
                                      if (!mounted) return;
                                      setState(() {
                                        if (submitOnSuggestionTap) {
                                          String newText = suggestion.toString();
                                          textField!.controller!.text = newText;
                                          if (unFocusOnItemSubmitted) {
                                            textField!.focusNode!.unfocus();
                                          }
                                          itemSubmitted!(suggestion);
                                          if (clearOnSubmit) {
                                            clear();
                                          }
                                        } else {
                                          String newText = suggestion.toString();
                                          textField!.controller!.text = newText;
                                          textChanged!(newText);
                                        }
                                      });
                                    }))
                          ]);
                        }).toList(),
                      )),
                    ))));
      }); 

PS: Above code is null safe and has lint issues resolved

from flutter-autocomplete-textfield.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.