Not able to change a value in one page with respect to the value from another page in flutter - flutter

i want to change the indexvalue (pictogramindex) of one page when we click nextbutton on another screen.I will explain briefly , I have 2 screens in my scenario the first screen contains an image and it's name , a textfield and nextbutton (i have provided a dummy data contains a list of image and it's names) the logic behind this is , when we complete the textfield box and click next button(after validate) the textfield value checks with the correctvalue which i was given in the dummy data and show it's synonym which also provided. when we click the next button we will go to another page which contains the correct answer(passed from first page) and a textfield in this the user can write about the correct answer ( validated) when click next button in this page (till this my applicationworks perfectly) i want to load the first page with it's index updated (+1) which i initialised as 0 (var pictogramindex=0). But in my case when coming back to first page the index is not updating it will automatically stores the initialised value. what i want is i want to update index on the first page when i click next button in the Second page .
my source code of first screen is shown here
class Pictogramscreen extends StatefulWidget {
final int length;
const Pictogramscreen({Key key, this.length}) : super(key: key);
#override
_PictogramscreenState createState() => _PictogramscreenState();
}
class _PictogramscreenState extends State<Pictogramscreen> {
#override
final _Key = GlobalKey<FormState>();
Color defaultcolor = Colors.blue[50];
Color trueColor = Colors.green;
Color falseColor = Colors.red;
Widget defcorrect = Text('');
var pictogramindex = 0;
TextEditingController usertitleInput = TextEditingController();
nextPictogram() {
setState(() {
pictogramindex++;
});
}
fillColor() {
setState(() {
usertitleInput.text == pictdata[pictogramindex]['pictcorrectword']
? defaultcolor = trueColor
: defaultcolor = falseColor;
});
}
correctText() {
setState(() {
usertitleInput.text == pictdata[pictogramindex]['pictcorrectword']
? defcorrect = Text(pictdata[pictogramindex]['pictsynonym'])
: defcorrect = Text(pictdata[pictogramindex]['pictcorrectword']);
});
}
reset() {
setState(() {
defaultcolor = Colors.blue[50];
defcorrect = Text('');
usertitleInput.clear();
});
}
void description(BuildContext ctx) {
Navigator.of(context).pushNamed('/user-description', arguments: {
'id': pictdata[pictogramindex]['pictid'],
'word': pictdata[pictogramindex]['pictcorrectword']
});
}
Widget build(BuildContext context) {
int length = pictdata.length;
return Scaffold(
body: pictogramindex < pictdata.length
? ListView(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20),
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Card(
margin: EdgeInsets.only(top: 20),
child: Image.network(
pictdata[pictogramindex]['pictimg']),
),
SizedBox(
height: 10,
),
Text(
pictdata[pictogramindex]['pictword'],
style: TextStyle(
fontSize: 25,
),
),
SizedBox(
height: 10,
),
//Card(
//color: Colors.blue,
// child: TextField(
// decoration: InputDecoration.collapsed(
// hintText: 'type here'),
//textAlign: TextAlign.center,
// onSubmitted: (value) {
// usertitleInput = value;
// print(usertitleInput);
// },
// ),
//),
Form(
key: _Key,
child: TextFormField(
controller: usertitleInput,
validator: (usertitleInput) {
if (usertitleInput.isEmpty) {
return 'Answer cannot be empty';
} else {
return null;
}
},
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.blueAccent),
borderRadius: BorderRadius.all(
Radius.circular(15),
)),
labelText: 'Type your Answer',
filled: true,
fillColor: defaultcolor,
),
onFieldSubmitted: (value) {
usertitleInput.text = value;
fillColor();
correctText();
print(usertitleInput.text);
}),
),
SizedBox(
height: 10,
),
defcorrect,
SizedBox(
height: 10,
),
RaisedButton(
onPressed: () {
if (_Key.currentState.validate()) {
description(context);
// nextPictogram();
reset();
}
//
//if (_Key.currentState.validate() == correctText()) {
// nextPictogram;
// }
},
child: Text('Next'),
)
],
),
),
],
)
: Center(
child: Text('completed'),
));
}
}
my source code of the second screen is show here
class Userinputscreen extends StatefulWidget {
final String id;
final String word;
const Userinputscreen({Key key, this.id, this.word}) : super(key: key);
#override
_UserinputscreenState createState() => _UserinputscreenState();
}
class _UserinputscreenState extends State<Userinputscreen> {
final _Keey = GlobalKey<FormState>();
TextEditingController userdescription = TextEditingController();
var pictogramindex;
void nextpict(BuildContext context) {
Navigator.of(context).pushNamed('/main-screen');
}
// void nextpict(BuildContext context, int index) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (ctx) => Pictogramscreen(
// index: i = 0,
// )));
// }
#override
Widget build(BuildContext context) {
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, String>;
final correctWord = routeArgs['word'];
return MaterialApp(
home: Scaffold(
body: ListView(children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 50),
child: Center(
child: Container(
padding: EdgeInsets.all(20),
margin: EdgeInsets.only(top: 100),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
correctWord,
style: TextStyle(fontSize: 26),
),
SizedBox(
height: 10,
),
Form(
key: _Keey,
child: TextFormField(
controller: userdescription,
validator: (userdescription) {
if (userdescription.isEmpty) {
return 'Answer cannot be empty';
} else {
return null;
}
},
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent),
borderRadius: BorderRadius.all(
Radius.circular(15),
)),
labelText: 'Type your Answer',
filled: true,
),
onFieldSubmitted: (value) {
userdescription.text = value;
print(userdescription.text);
}),
),
SizedBox(
height: 10,
),
RaisedButton(
onPressed: () {
if (_Keey.currentState.validate()) {
nextpict(context);
}
},
child: Text('Next'),
)
],
),
),
),
),
])),
);
}
}

If I get it right, you basically want to tell the initial page that it's state is updated(the index) elsewhere. You basically need to make your app "reactive".
As is said in Google Developers Tutorial:
One of the advantages of Flutter is that it uses reactive views, which you can take to the next level by also applying reactive principles to your app’s data model.
Use some sort of state management. You need to choose from and use either Bloc, InheritedWidget and InheritedModel, Provider(ScopedModel), or the like.
Check this article on flutter about state management, or this for a complete list of approaches

Related

Dynamic List View Builder error - Black Screen List View Builder

I'm currently working on a part of a project in which in I will be typing in an entry to the provided Text Form Field and the typed entry will be displayed in a list view builder dynamically (meaning the list grows the more entry the user gives).
However, I came across this error where right after I entered an entry, the screen changes straight to black [PLEASE SEE VIDEO or PICTURES (attached)]. If you slow down the video, you can catch a glimpse that the entered input was indeed displayed in the box, but the screen just switches to black right away. Any ideas why this happens? What can I fix? What's my error?
The following is a time stamp screenshot of what the error looks like (in case the video does not load):
part1
part2
part3
part4
The following is my code:
import 'package:english_words/english_words.dart';
import 'package:globesisters_internship_project/screens/invite_list.dart';
import 'package:flutter/material.dart';
/*GLOBAL VARIABLE*/
//TextFormField for Friends Name
var _friendsName;
final _friendsNameController = TextEditingController();
class InviteFriendsPage extends StatefulWidget {
#override
State<InviteFriendsPage> createState() => _InviteFriendsPageState();
}
class _InviteFriendsPageState extends State<InviteFriendsPage> {
#override
void dispose1() {
_friendsNameController.dispose();
super.dispose();
}
List<String> list_of_friends = []; **//THIS IS THE ENTRY LIST!!**
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Column(children: <Widget>[
SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(border: Border.all(color: Colors.black)),
width: 300,
height: 260,
child: ListView.builder( **//THIS IS THE LISTVIEW BUILDER**
shrinkWrap: true,
itemCount: list_of_friends.length,
itemBuilder: (context, index) {
return Card(
//margin: EdgeInsets.all(5),
child: ListTile(
title: Text(list_of_friends[index]),
));
},
)),
SizedBox(
height: 10.0,
), //spacing
Container(
margin: EdgeInsets.only(
left: 20,
right: 20,
),
child: Column(
children: <Widget>[
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
validator: (value) {
if (value!.isEmpty)
return 'Please enter a valid Name';
else
return null;
},
controller: _friendsNameController,
decoration: InputDecoration(
labelText: "Invite your friend!",
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
),
SizedBox(height: 10.0),
SendInviteButton(context),
],
),
),
],
))
]);
}
//
/* BUTTON */
OutlinedButton SendInviteButton(BuildContext context) {
int count = 0;
**//THIS IS MY ATTEMPT TO SET-STATE FOR DYNAMIC LIST ENTRY**
void addFriends(String friends) {
setState(() {
list_of_friends.add(friends);
});
}
return OutlinedButton(
style: OutlinedButton.styleFrom(minimumSize: const Size(400, 50)),
onPressed: () {
if (_formKey.currentState!.validate()) {
count++;
final addedFriend = _friendsNameController.text;
//widget.add_friend(addedFriend);
addFriends(addedFriend);
Navigator.of(context).pop();
}
},
child: Text(
"Send Invite".toUpperCase(),
style: const TextStyle(color: Colors.cyan, fontWeight: FontWeight.bold),
),
);
}
}

Flutter with Firebase, Search by multiple queries

I am trying to create a search feature that allows users to search by their username, email, designation or company. I intend to let users have the flexibility of typing any of those into the search bar and search for their target. However, what i am facing is that my code below only calls on the first function and displays results only for username (username is the first function here, can be interchanged with other functions and it will call according to that). my code is below and thanks for all the help in advance.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:ib_club/services/database.dart';
import 'package:ib_club/widgets/widget.dart';
class SearchScreen extends StatefulWidget {
#override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
DatabaseMethods databaseMethods = new DatabaseMethods();
TextEditingController searchTextEditingController =
new TextEditingController();
QuerySnapshot<Map<String, dynamic>> searchSnapshot;
initiateUsernameSearch() {
databaseMethods
.getUserByUsername(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateEmailSearch() {
databaseMethods
.getUserByEmail(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateDesignationSearch() {
databaseMethods
.getUserByDesignation(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateCompanySearch() {
databaseMethods
.getUserByCompany(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateSearch() {
initiateUsernameSearch();
initiateEmailSearch();
initiateDesignationSearch();
initiateCompanySearch();
}
// Create chatroom, send user to conversation screen, pushreplacement
/*createChatroomAndStartConversation(String userUsername) {
List<String> users = [
userUsername,
];
databaseMethods.createChatRoom();
}*/
Widget searchList() {
return searchSnapshot != null
? ListView.builder(
itemCount: searchSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return SearchTile(
userUsername: searchSnapshot.docs[index].data()["username"],
userEmail: searchSnapshot.docs[index].data()["email"],
userDesignation:
searchSnapshot.docs[index].data()["designation"],
userCompany: searchSnapshot.docs[index].data()["company"],
);
})
: Container(
/*child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
const Color(0XffFBD24F))))*/
);
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body: Container(
child: Column(children: [
SizedBox(
height: 16,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFF)
]),
borderRadius: BorderRadius.circular(40)),
child: TextField(
controller: searchTextEditingController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: "Search User",
hintStyle: TextStyle(color: Colors.white54),
border: InputBorder.none),
),
)),
GestureDetector(
onTap: () {
initiateSearch();
},
child: Container(
height: 45,
width: 45,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFF)
]),
borderRadius: BorderRadius.circular(45)),
child: Icon(Icons.search,
size: 30, color: const Color(0XffFBD24F))),
),
],
),
),
searchList()
]),
));
}
}
class SearchTile extends StatelessWidget {
final String userUsername;
final String userEmail;
final String userDesignation;
final String userCompany;
SearchTile(
{this.userUsername,
this.userEmail,
this.userDesignation,
this.userCompany});
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [const Color(0x36FFFFFF), const Color(0x0FFFFFF)]),
borderRadius: BorderRadius.horizontal()),
child: Row(children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
userUsername,
style: mediumWhiteTextStyle(),
),
Text(
userEmail,
style: mediumWhiteTextStyle(),
),
Text(
userDesignation,
style: mediumWhiteTextStyle(),
),
Text(
userCompany,
style: mediumWhiteTextStyle(),
)
],
),
),
Spacer(),
GestureDetector(
onTap: () {},
child: Container(
decoration: BoxDecoration(
color: const Color(0XffFBD24F),
borderRadius: BorderRadius.circular(30)),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text(
"Message",
style: mediumTextStyle(),
),
),
)
]),
);
}
}
I could not give a straight answer base on your code but I have a search concept, which I am hoping to help you in any way.
In my case, I always fetch all my item data from firebase and put it in "overallItems" (which is a List of Item Model). From there, I can now start to filter/search my list and return the result.
The concept I use is like this:
List<Item> filterItems() {
//first, I would want to have a temporary holder for a copy of my original items
final List<Item> itemHolder = List<Item>.from(overallItems);
//If user has title input on the search bar
if (titleKeyword.text != '') {
//then this for loop will iterate to all my data
for (final item in List<Item>.from(itemHolder)) {
//will check each title from the list
if (!item.title.toLowerCase().contains(titleKeyword.text.toLowerCase())) {
//elimate items that did not qualify
itemHolder.remove(item);
}
}
}
//so after the first if, itemHolder will be left with the result....
//now, I would also like to search the seller name.
//then, I would just have to repeat the process above
//Searching for Seller Name
if (sellerKeyword.text != '') {
for (final item in List<Item>.from(itemHolder)) {
if (!item.sellerName
.toLowerCase()
.contains(sellerKeyword.text.toLowerCase())) {
itemHolder.remove(item);
}
}
}
//the itemHolder list will have the result
return itemHolder;
}
In the end, we will have the search result after the elimination process.

The following _CastError was thrown building NoteAdder(dirty, state: _NoteAdder#76214):Null check operator used on a null value

The error (given in the title) was thrown when I ran the app.
Here is my code
class NoteAdder extends StatefulWidget {
#override
_NoteAdder createState() => _NoteAdder();
}
class _NoteAdder extends State<NoteAdder> {
Note? note;
TextEditingController titleController = TextEditingController();
TextEditingController descriptionController = TextEditingController();
#override
Widget build(BuildContext context) {
titleController.text = note!.title!;
descriptionController.text = note!.description!;
return AlertDialog(
backgroundColor: Colors.lime,
content: Column(
children: [
const Text(
'ADD NOTE',
style: TextStyle(fontSize: 25),
),
const SizedBox(height: 30),
Container(
alignment: Alignment.topLeft,
child: const Text('Title:'),
),
TextField(
controller: titleController,
decoration: InputDecoration(
border: UnderlineInputBorder(),
),
),
const SizedBox(height: 30),
Container(
alignment: Alignment.topLeft,
child: const Text('Description:'),
),
TextField(
controller: descriptionController,
maxLines: 13,
decoration: InputDecoration(
border: UnderlineInputBorder(),
),
),
const SizedBox(height: 35),
Container(
alignment: Alignment.center,
child: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.red),
onPressed: () {
setState(() {
save();
});
},
child: const Text('Save')))
],
));
}
void save() async {
note?.date = DateFormat.yMMMd().format(DateTime.now()) as DateTime?;
if (note?.id != null) {
await NoteDatabaseHelper.update(note!)??0;
} else {
await NoteDatabaseHelper.insert(note!)??0;
}
}
}
I am a bit new to flutter. Please help me to solve this problem
Link to my complete project: https://github.com/SayanBanerjee09082002/Daily_Utility
Note: The add screen appears when I press a floating action button. The app runs ok until I hit that button.
Since you wrote Note? note;, note == null so trying to use it with null check like this note?.date = DateFormat.yMMMd().format(DateTime.now()) as DateTime?; will throw error. Now I don't know what the constructor of your class Note look like so my answer may not be accurate; but as answer, I will advice you to do either:
Note? note = Note(); //I don't know the structure of the constructor, so you have to deal with that part
or inside save()
if(note != null) {
note.date = DateFormat.yMMMd().format(DateTime.now()) as DateTime;
}

Empty container consuming space in gridview builder when searching through a list

Code :
class MobileCourses extends StatefulWidget { const MobileCourses({ Key? key }) : super(key: key);
#override _MobileCoursesState createState() =>
_MobileCoursesState(); }
class _MobileCoursesState extends State<MobileCourses> { String searchCourse = ""; TextEditingController searchController = TextEditingController(); #override Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
searchBar(),
Expanded(
child: Container(
padding: EdgeInsets.all(15),
child : FutureBuilder(
future: Networking.getAllCourses(),
builder: (_,snapshot)
{
if(snapshot.hasData)
{
List<SpecificCourse>? specificCourse = snapshot.data as List<SpecificCourse>?;
return GridView.builder(
physics: BouncingScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 15
),
itemCount: specificCourse![0].courses.length ,
itemBuilder: (_,index)
{
return specificCourse[0].courses[index].course.toLowerCase().contains(searchCourse) ? MobileContainer(course: specificCourse[0].courses[index].course):Container(color: Colors.red,),
// over here i am searching for my required course
},
);
}
else
{
return CircularProgressIndicator();
}
}
),
),
),
],
),
);
}
}
Search Bar :-
Widget searchBar() {
return Padding(
padding: const EdgeInsets.only(left : 15.0,right: 15.0 , top: 10.0 ,bottom: 10.0),
child: Container(
child: TextField(
decoration: InputDecoration(
hintText: "Search...",
prefixIcon: Icon(Icons.search)
),
onChanged: (value){
setState(() {
searchCourse = value.toLowerCase();
});
},
controller: searchController,
),
),
);
}
I want to implement search function inside my gridview and i have tried to implement it in the above code and the ui is looking something like this
but when i search "m" it should return me only MBA but it is returning container too i do not want these container(colored in red) i only want MBA .......I have explicity given container red for better understanding
Container without red color
i only want to return MBA but the empty container is consuming space. Please help ! and sorry for these big images i do not know how to decrease their size
Try to below code its working for me for ListView.Builder Please try to change it Gridview hope it helps you:
Create one class with your JSON Data :
class User {
String name;
int id;
int totalLeads;
User({
this.id,
this.name,
this.totalLeads,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['name'] as String,
id: int.parse(json['userId']),
totalLeads: int.parse(json['total']),
);
}
}
Create one class that you declare voidCallback function:
class Debouncer {
final int milliseconds;
VoidCallback action;
Timer _timer;
Debouncer({this.milliseconds});
run(VoidCallback action) {
if (null != _timer) {
_timer.cancel();
}
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
}
Create Stateful Widget Class
class AllAgents extends StatefulWidget {
AllAgents() : super();
#override
AllAgentsState createState() => AllAgentsState();
}
class AllAgentsState extends State<AllAgents> {
final _debouncer = Debouncer(milliseconds: 500);
List<User> users = [];
List<User> filteredUsers = [];
static String url = 'your API url here';
static Future<List<User>> getAllLeagentsList() async {
try {
final response = await http.get(url);
if (response.statusCode == 200) {
List<User> list = parseAgents(response.body);
return list;
} else {
throw Exception('Error');
}
} catch (e) {
throw Exception(e.toString());
}
}
static List<User> parseAgents(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
#override
void initState() {
super.initState();
getAllLeagentsList().then((usersFromServer) {
setState(() {
users = usersFromServer;
filteredUsers = users;
});
});
}
// Declare Your Widget here
Column(children:[
//Search Bar to List of typed User
Container(
padding: EdgeInsets.only(top: 20, left: 20, right: 20),
child: TextField(
textInputAction: TextInputAction.next,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: Colors.grey,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: BorderSide(
color: Colors.blue,
),
),
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
contentPadding: EdgeInsets.all(15.0),
hintText: 'Search ',
),
onChanged: (string) {
_debouncer.run(() {
setState(() {
filteredUsers = users
.where((u) => (u.name
.toLowerCase()
.contains(string.toLowerCase())))
.toList();
});
});
},
),
),
//Lists of Agents
Expanded(
child: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
padding: EdgeInsets.only(top: 20, left: 20, right: 20),
itemCount: filteredUsers.length,
itemBuilder: (BuildContext context, int index) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
side: BorderSide(
color: Colors.grey[300],
),
),
child: Padding(
padding: EdgeInsets.all(5.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ListTile(
leading: Container(
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: Colors.white,
border: Border.all(color: Colors.blue),
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 2.0,
spreadRadius: 1.0,
offset: Offset(
1.0,
1.0,
), // shadow direction: bottom right
)
],
),
child: Text(filteredUsers[index].name[0]),
),
title: Text(
filteredUsers[index].name,
style: TextStyle(fontSize: 16),
),
)
],
),
),
);
},),),
],),
}
here is my screen without search ->
here is my screen with search ->

Flutter Dynamically insert and remove `TextFormField` from UI

I'm trying to insert TextFormField on a click to take the name of the student. This thing is working fine. But the problem is when I integrate remove functionality than it's not working as expected.
I did take List<Student> to insert and remove items and converted this List into Map to plot items to UI and update user input name value to a specific indexed Student object value.
If we try adding items and removing them serially than it'll work fine but the only issue is when I remove a single item from in-between it will only update my List and Map but UI will not get updated. This is my code
import 'package:dynamic_input_add_flutter/student.dart';
import 'package:flutter/material.dart';
class SingleListUse extends StatefulWidget {
static final String tag = 'single-list-use';
#override
_SingleListUseState createState() => _SingleListUseState();
}
class Student1 {
String _name;
int _sessionId;
Student1(this._name, this._sessionId);
String get name => _name;
set name(String value) {
_name = value;
}
int get sessionId => _sessionId;
set sessionId(int value) {
_sessionId = value;
}
#override
String toString() {
return 'Student $_name from session $_sessionId';
}
}
class _SingleListUseState extends State<SingleListUse> {
List<Student1> _studentList = [];
Map<int, Student1> _studentMap = {};
void _addNewStudent() {
setState(() {
_studentList.add(Student1('', 1));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.done,
color: Colors.white,
),
onPressed: () {
if (_studentList.length != 0) {
_studentList.forEach((student) => print(student.toString()));
} else {
print('map list empty');
}
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButtonAnimator: FloatingActionButtonAnimator.scaling,
appBar: AppBar(
title: Text('Single Map Use'),
actions: <Widget>[
FlatButton(
onPressed: () {
_addNewStudent();
},
child: Icon(
Icons.add,
color: Colors.white,
),
)
],
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0),
child: Builder(
builder: (context) {
print("List : ${_studentList.toString()}");
_studentMap = _studentList.asMap();
print("MAP : ${_studentMap.toString()}");
return ListView.builder(
itemCount: _studentMap.length,
itemBuilder: (context, position) {
print('Item Position $position');
return Padding(
padding: EdgeInsets.only(top: 5.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
initialValue: _studentMap[position].name.length != 0
? _studentMap[position].name
: '',
onFieldSubmitted: (name) {
setState(() {
_studentList[position].name = name;
});
},
decoration: InputDecoration(
hintText: 'enter student name',
hintStyle: TextStyle(
fontSize: 16.0,
color: Colors.black26,
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black12,
),
borderRadius: BorderRadius.all(
Radius.circular(15.0),
),
),
),
),
),
IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
setState(() {
_studentList.removeAt(position);
});
},
)
],
),
);
},
);
},
),
),
);
}
}
The first image is when we add a Student name in plus icon click.(every item in List is a TextFormField. When I remove the second item from UI it will remove 3rd one while technically from data structure that I've used (List & Map) it's removing 2nd (and that's ok). I have an issue of displayed UI after we perform any delete from between.
Since this is state-full widget make a variable bool showTextFormField = false in state class
now in widget use if(showTextFormField) <Widget>
now on button click
setState(){
showTextFormField = true;
}