I want to implement suggestions inside textFormField. same as below
So, I've searched regarding this but with no success. Everywhere I've got is suggestions inside list. Which is easy to do. If you have any suggestions then please add your valuable answer and comment.
Here is my code
Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: controller,
onFieldSubmitted: (value) {},
onChanged: (value) {
displaySuggestionInList(value);
},
),
const SizedBox(height: 30),
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 100,
maxWidth: 200,
minWidth: 200,
minHeight: 100,
),
child: ListView.builder(
shrinkWrap: true,
itemCount: dashboardLayouts!.length,
itemBuilder: (context, index) {
return Text((dashboardLayouts![index]['dashBoardData']
as DashboardInfo)
.commonName
.toString());
},
),
)
],
),
What you need to create is a Type-Ahead Widget. To do that, you will firstly create the normal List suggestion StatefulWidget. While on the filter function you should update the hint with the first value from the suggestion list. This way you can call the hint value and place it anywhere on your screen. Unfortunately for us, flutter doesn't allow the update showing of hint within the input field while typing.
Although I made an example for you to get the idea.
class AutocompleteExample extends StatefulWidget {
const AutocompleteExample({super.key});
#override
State<AutocompleteExample> createState() => _AutocompleteExampleState();
}
class _AutocompleteExampleState extends State<AutocompleteExample> {
TextEditingController controller = TextEditingController();
List suggestionList = [];
String hint = "";
List<String> nameList = <String>[
'aardvark',
'bobcat',
'chameleon',
'Nathaniel Bond',
'Taylor Story',
'Lamont Padilla',
'Jamia Sun',
'Nikki Reichert',
'Tea Holguin',
'Rafael Meade',
'Mercedez Goad',
'Aileen Foltz',
'Bryant Burt',
];
void typeAheadFilter(String value) {
suggestionList.clear();
if (value.isEmpty) {
setState(() {});
return;
}
for (String name in nameList) {
if (name.toLowerCase().contains(value)) {
suggestionList.add(name);
}
}
if (suggestionList.isNotEmpty) {
var firstSuggestion = suggestionList[0];
setState(() => hint = firstSuggestion);
}
setState(() {});
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: controller,
onFieldSubmitted: (value) {},
onChanged: (value) => typeAheadFilter(value),
decoration: InputDecoration(
hintText: hint,
labelText: hint.isEmpty ? "Search" : hint,
alignLabelWithHint: true,
hintTextDirection: TextDirection.rtl),
),
const SizedBox(height: 10),
if (suggestionList.isNotEmpty || controller.text.isNotEmpty) ...[
Expanded(
child: ListView.separated(
padding: const EdgeInsets.all(10),
shrinkWrap: true,
itemCount: suggestionList.length,
separatorBuilder: (context, index) => const Divider(),
itemBuilder: (context, index) {
return Text((suggestionList[index]));
},
),
)
] else ...[
Expanded(
child: ListView.separated(
padding: const EdgeInsets.all(10),
shrinkWrap: true,
itemCount: nameList.length,
separatorBuilder: (context, index) => const Divider(),
itemBuilder: (context, index) {
return Text((nameList[index]));
},
),
)
]
],
);
}
}
Related
//code of the screen
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
itemCount: controller.favDestinationList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
width: MediaQuery
.of(context)
.size
.width * 0.9,
child: Row(
children: [
IconButton(
icon:FaIcon(controller.favDestinationList[index].isfav?
FontAwesomeIcons.solidHeart : FontAwesomeIcons.heart,
color: secondaryHeaderColor,),
onPressed: () {
controller.changeStatus(
controller.favDestinationList[index].isfav);
print(controller.favDestinationList[index].isfav);
},
);
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(controller.favDestinationList[index].name),
)
]
,
)
,
);
}
),
///////code of the screen
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
itemCount: controller.favDestinationList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
width: MediaQuery
.of(context)
.size
.width * 0.9,
child: Row(
children: [
IconButton(
icon:FaIcon(controller.favDestinationList[index].isfav?
FontAwesomeIcons.solidHeart : FontAwesomeIcons.heart,
color: secondaryHeaderColor,),
onPressed: () {
controller.changeStatus(
controller.favDestinationList[index].isfav);
print(controller.favDestinationList[index].isfav);
},
);
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(controller.favDestinationList[index].name),
)
]
,
)
,
);
}
),
/////////////////controller class
class SearchFavoriteController extends GetxController{
var favDestinationList=[].obs;
#override
void onInit() {
// TODO: implement onInit
super.onInit();
getFavDestination();
}
getFavDestination() async{
try{
var destination=await Api().getfavdestinations();//call api
favDestinationList.assignAll(destination);
}catch(e){
Get.snackbar('title', e.toString());
}
}
changeStatus(bool isfavorite) {
isfavorite = !isfavorite;
update();
}
}
/////////////api
List<FavoriteModel> getfavdestinations() {
return [
FavoriteModel( id: '1',name: 'Germany', isfav: false),
FavoriteModel( id: '2',name: 'Turkey', isfav: true),
FavoriteModel( id: '3',name: 'Jordan', isfav: false),
FavoriteModel( id: '4',name: 'London', isfav: false)
].obs;
}
Your question is not very clear, and you have to Rephrase it
However, i think there isn't any Observer Widget or GetXBuilder in your view
try to wrap the listView.Builder with one of them, it should works
I'm trying to display items based on the selected category but I'm not finding the right way to do that.
I suppose the id of the category need to match the categoryId of the item but I'm not getting there.
Here the code for the backend_api:
Future<List<Item>> fetchItems(
{int? categoryId,
String? zipcode,
String? searchText,
String? radius}) async {
var path =
categoryId != null ? "/item/list/category/$categoryId" : "/item/list";
path += zipcode != null ? "/zipcode/$zipcode" : "";
path += "?";
if (searchText != null) {
path += "&search=$searchText";
}
if (radius != null) {
path += "&radiusInKm=$radius";
}
final http.Response response = await _httpClient.get(path);
return jsonDecode(utf8.decode(response.bodyBytes))
.map<Item>((json) => Item.fromJson(json))
.toList();
}
Here the code for displaying the items:
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: const ClampingScrollPhysics(),
child: Row(
children: [
BlocBuilder<ItemCategoriesBloc, ItemCategoriesState>(
builder: ((context, state) {
if (state is ItemCategoriesLoadedState) {
List<MapEntry<int, Category>> categoryList =
List.from(state.categories.entries);
return Container(
width: 800,
child: FormBuilderChoiceChip(
decoration: const InputDecoration(border: InputBorder.none),
selectedColor: MyTheme.primary,
alignment: WrapAlignment.spaceEvenly,
direction: Axis.horizontal,
initialValue: categoryList.map((value) => value).toList(),
name: 'filter_category',
options: categoryList
.map(
(category) => FormBuilderFieldOption(
value: category.value.id,
child: Text(category.value.name),
),
)
.toList(),
//onChanged: showFilteredItems(),
),
);
}
return Container();
}),
),
],
),
),
Expanded(
child: RefreshIndicator(
onRefresh: onRefresh ?? () async {},
child: GridView.builder(
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: aspectRatio,
crossAxisCount: crossAxisCount,
),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return _ItemListView(
onTap: onTap,
item: items[index],
// Todo: add ngos
);
},
),
),
),
],
);
Thank you in advance for your help!
How can we create Gridview with the user input? the user is allowed to enter the no of rows and columns.
class Class extends StatefulWidget {
#override
_ClassState createState() => _ClassState();
}
class _ClassState extends State<Class> {
TextEditingController row = TextEditingController();
TextEditingController column = TextEditingController();
int rowC = 2;
int colC = 2;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
height: 500,
child: GridView.builder(
itemCount: colC * rowC,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: rowC,childAspectRatio: colC*rowC/2 ,crossAxisSpacing: 10,mainAxisSpacing: 10),
shrinkWrap: true,
itemBuilder: (context, index) => Container(
color: Colors.greenAccent,
),
),
),
Text("Row"),
TextField(
controller: row,
),
SizedBox(height: 20,),
Text("Column"),
TextField(
controller: column,
),
SizedBox(height: 20,),
FlatButton(onPressed: (){
rowC = int.parse(row.text);
colC = int.parse(column.text);
setState(() {
});
}, child: Container(
color: Colors.purple,
padding: EdgeInsets.all(20),
child: Text("Add")))
],
),
);
}
}
You can achieve your requirement by using the GridView.builder.
GridView.builder(
shrinkWrap: true,
itemCount: (rowCount * ColumnCount),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: ColumnCount),
itemBuilder: (context, index) {
return Container(
child: Text(index.toString()),
);
}, );
Every user input you must to refresh the widget.
I have a list of custom TextFormField's that i added to them a delete icon
all I am trying to do is when I press the delete button it will be deleted from the list and the view
i tried adding a function to my form field with no success
I think my approach isn't the best way to implement what i want, I am open to any idea
here is the code
import 'package:flutter/material.dart';
typedef DeleteCallback = void Function(Key key);
class DynamicFormField extends FormField<String>{
DynamicFormField({
Key key,
FormFieldSetter<String> onSaved,
FormFieldValidator<String> validator,
String initialValue = "",
bool autovalidate = false,
DeleteCallback onDelete(Key key),
}) : super(
onSaved: onSaved,
validator: validator,
initialValue: initialValue,
autovalidate: autovalidate,
builder: (FormFieldState<String> state) {
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
flex: 5,
child: TextFormField(
decoration: const InputDecoration(
hintText: 'Enter Player Name',
),
onSaved: onSaved,
validator: validator,
initialValue: initialValue,
autovalidate: autovalidate,
),
),
IconButton(
icon: Icon(Icons.delete_outline),
onPressed: onDelete(key)
),
],
);
}
);
}
DynamicFormField(
key: UniqueKey(),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onSaved: (input) => {players.add(Player(input))},
onDelete: f,
),
);
}
void f(Key key){
fields.removeWhere((item) => item.key == key);
}
tnx
I solved it using ListView builder
import 'package:flutter/material.dart';
import 'package:rummy/models/player.dart';
import 'package:rummy/screens/game_screen.dart';
class NewGame extends StatefulWidget {
NewGame({Key key}) : super(key: key);
#override
_NewGameState createState() => _NewGameState();
}
class _NewGameState extends State<NewGame> {
final _formKey = GlobalKey<FormState>();
List<Widget> fields;
List<Player> players;
_NewGameState() {
players = new List<Player>();
fields = new List();
print(players);
fields.add(generateField());
}
Widget generateField() {
return TextFormField(
decoration: const InputDecoration(
hintText: 'Enter Player Name',
),
onSaved: (input) => {players.add(Player(input))},
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: <Widget>[
Form(
key: _formKey,
child: Expanded(
child: ListView(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height,
child: Builder(
builder: (BuildContext context) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: fields.length,
itemBuilder:
(BuildContext context, int postion) {
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: fields[postion],
),
IconButton(
icon: Icon(Icons.delete_outline),
onPressed: () => {
setState(() {
print(postion);
fields.removeAt(postion);
})
}),
],
);
},
);
},
),
)
],
),
)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
print("asdasd");
if (_formKey.currentState.validate()) {
players.clear();
_formKey.currentState.save();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GameScreen(players),
));
} else
print(_formKey.currentState.validate());
},
child: Text('Submit'),
),
RaisedButton(
onPressed: () {
setState(() {
fields.add(generateField());
});
},
child: Text('Add New Player'),
),
],
),
],
mainAxisAlignment: MainAxisAlignment.center,
),
),
),
);
}
}
I used this
https://github.com/MobMaxime/Flutter-To-Do-App/blob/master/lib/screens/todo_list.dart
I just started working with flutter, so far so good. But I have an issue at the moment:
I wish to make a check Icon visible when I tap on the child view in a Listview.builder widget
child: ListView.builder(
shrinkWrap: true,
itemCount: users.length,
itemBuilder: (BuildContext context, int index){
// final item = feeds[index];
return FlatButton(
onPressed:(){
setState(() {
_selected = !_selected;
choosenUser = users[index];
print("the user:${users[index].fullName},$_selected");
});
},
child:(_selected) ? UserCard(users[index], _selected):UserCard(users[index], _selected)
);
}
)
inside UserCard there is a check Icon I wish to show or hide when the FlatButton in the ListView.builder is clicked.
I passed in a boolean to the UserCard but it does not work
class UserCard extends StatefulWidget{
UserItem userItem;
bool selected;
UserCard(this.userItem, this.selected);
#override
_UserCard createState() => _UserCard(userItem,selected);
}
class _UserCard extends State<UserCard>{
UserItem _userItem;
bool selected;
_UserCard(this._userItem, this.selected);
#override
Widget build(BuildContext context) {
// TODO: implement build
return /* GestureDetector(
onTap: () {
setState(() {
selected = !selected;
print("user:${_userItem.fullName}");
});
},
child:*/Container(
height:80 ,
child:
Column(
children: <Widget>[
Row(
children: <Widget>[
_userItem.profileUrl != null? CircleAvatar(child: Image.asset(_userItem.profileUrl),): Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.white70,
shape: BoxShape.circle,
image: DecorationImage(
image:AssetImage('assets/plus.png') //NetworkImage(renderUrl ??'assets/img.png')
)
),
),
SizedBox(width: 30,),
Expanded(
flex: 1,
child:
Container(
child:
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 12,),
_userItem.fullName != null? Text(_userItem.fullName, style: TextStyle(fontSize: 18)): Text('Anjelika Thompson', style: TextStyle(fontSize: 18),),
SizedBox(height: 12,),
Row(
//crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(child: Icon(Icons.location_on),alignment: Alignment.topLeft,),
SizedBox(width: 10,),
_userItem.distance_KM.toString() != null ? Text(_userItem.distance_KM.toString()):Text('48.7 km')
]),
],
),
],
)
),
),
SizedBox(width: 0,),
selected ? Icon(Icons.check,color: Colors.red,size: 40,):SizedBox(child: Text('$selected'),)
],
),
Container(
height: 0.5,
color: Colors.grey,
)
],
) ,
// )
);
}
}
Please what am I doing wrong here
Save your selections in list of Boolean.
list<bool> selected = list<bool>();
child: ListView.builder(
shrinkWrap: true,
itemCount: users.length,
itemBuilder: (BuildContext context, int index){
// final item = feeds[index];
return FlatButton(
onPressed:(){
setState(() {
selected[index] = !selected[index];
choosenUser = users[index];
print("the user:${users[index].fullName},$_selected");
});
},
child:UserCard(users[index], selected[index])
);
}
)
so I had to go a different route to fix the issue in my code. here is my code:
in my model class called UserItem, I introduced another parameter called selectedd
class UserItem{
String fullName, profileUrl;
double distance_KM;
bool selected;
UserItem(this.fullName, this.profileUrl, this.distance_KM, this.selected);
}
since am using static values for now, i passed in "false"
List<UserItem> users = []
..add(UserItem("Edward Norton","assets/profile_img.png", 12.0, false))
..add(UserItem("Gary Owen","assets/img.png", 21, false))
..add(UserItem("Eddie L.","assets/img_details.png", 12.7, false))
..add(UserItem("Carlos Snow","assets/header_user.png", 1.3, false))
..add(UserItem("Idibbia Olaiya","assets/profile_img.png", 0, false));
then when user clicks on any of the child item the selected value that was already set as false will be updated. here is my Listview.builder widget:
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: users.length,
itemBuilder: (BuildContext context, int index){
// final item = feeds[index];
return
Stack(
children: <Widget>[
Container(
child: FlatButton(
onPressed:(){
setState(() {
selected = !selected;
users[index].selected =selected;
// _theIcon = selected ? _theIcon : Icon(Icons.check,color: Colors.grey,size: 40,);
choosenUser.add(users[index]) ;
// print("the user:${users[index].fullName},$selected");
// child_card(users[index], selected,index);
});
}, child:child_card(users[index]),
),
)
],
);
}
)
)
Widget child_card(UserItem user){
// print("the user:${user.fullName},$selected");
return UserCard(user);
}
Hope this helps someone.