Dart, Flutter List onTap to get index of taped item - list

i created a search delegate class and what i want sounds logically simple but i cant wrap my head around it as i am new programming
i want to get the text or maybe i should say string of the text in the listTile i tap on ,
then pass that text to the showResult of search delegate and view it in a text widget
... here is my code
import 'package:flutter/material.dart';
import 'package:schooler/style/const.dart';
//follow steps 1 - 3
class DataSearch extends SearchDelegate<String> {
final List<String> languages = [//3.here is my list
'dart',
'Csharp',
'Java',
'JavaScript',
'C++',
'go ',
'python',
'php'
];
final List<String> recentSearch = [
'go ',
'python',
'php',
];
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
)
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
return Scaffold(
body: ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(),
Text(languages[0].substring(query.length)),//2.i want to return the gotten index here
],
),
],
),
);
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestionList = query.isEmpty
? recentSearch
: languages.where((element) => element.startsWith(query)).toList();
return ListView.builder(
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context); //1.when i tap the item on the listTile i want it to get the index of the taped item
},
leading: query.isEmpty
? Icon(
Icons.history,
)
: Icon(Icons.search),
title: RichText(
text: TextSpan(
text: suggestionList[index].substring(
0,
query.length,
),
style: TextStyle(
color: kBlackColor,
fontWeight: kBold,
),
children: [
TextSpan(
text: suggestionList[index].substring(query.length),
style: TextStyle(color: kGreyColor),
),
],
),
),
),
itemCount: suggestionList.length,
);
}
}
here if i tap on 'go' it should get get the text and pass it to the showResult
here is my show result ..but i just hard coded my 'list[0]index in there' i guess what i am trying to say is get the text from the item i taped and show it here

First lets fix your itemBuilder in your ListView so it indexes each element and then add that index into your showResults() function call so you have access to it:
ListView.builder(
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) => ListTile( // Add index here to pass the index to the builder.
onTap: () {
showResults(context, index); // Add the index to function call
},
Just be sure your showResults() function is modified to accept an int index parameter, and while I dont see that function, I am assuming it calls buildResults() at some point which needs to be modified to accept an index:
#override
Widget buildResults(BuildContext context, int index) {
return Scaffold(
body: ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(),
Text(languages[index].substring(query.length)),// Use the index here to return the desired text
],
),
],
),
);
}

Related

I'm new to flutter, trying to add a word to a list on btn click (the word comes from a text field). I then want the list to show on the page

Here's the image
If you look image, there's a text field and an add button at the bottom right. I want the user to enter the word and add that to a list using that button.
In order to access the value from the text field, I used (TextEditingController)
Please find the code for the widget below.
FYI: This widget gets called when an icon is pressed on its previous page
final wordList = []; // list that I'm trying to render
Widget _doSomething() {
setState(() async => wordList.add(await Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Enter Something..'),
),
body: TextField(
controller: myController,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Add word',
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pop(context, myController.text);
},
tooltip: "Toggle input value",
child: const Icon(Icons.add),
),
);
}))));
return _getList();
}
Above, I return _getList(). _getList() is another widget where I have the list view code in order to display the word list values in the same page. (code below)
Widget _getList() {
return Scaffold(
body: ListView.builder(
itemCount: wordList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(wordList[index]),
);
},
),
);
}
I apologize if something is unclear. Please feel free to ask me for more explanation. Thanks for you help.
First you do not need to use new when creating instance of class. So new Text() will become Text().
Second, if you use navigate use the .of() constructor, it will change your current screen. You can use the Navigator.push() method. The function would be async and would return of void. You can just retrun the widget in your main widget.
third, why are you returning a whole MaterialApp in a function. it should be in your main.dart.
void _doSomething() async {
wordList.add(await Navigator.
.push(context,MaterialPageRoute<void>(builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Enter Something..'),
),
body: TextField(
controller: myController,
decoration: InputDecoration(
border: OutlineInputBorder(), hintText: 'Add word',),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pop(context, myController.text);
},
tooltip: "Toggle input value",
child: const Icon(Icons.add),
),
);
})));
setState(()=> wordList = wordList);
}
For get list:
Widget _getList() {
return Scaffold(
body: ListView.builder(
itemCount: wordList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(wordList[index]),
);
},
),
);
}

How to avoid overwriting a List Item when using the same name?

In my project the user can add and edit List Items. The Problem is, that if the user add a List item with an already existing List name, the old one gets overwritten, with the error 'Multiple widgets used the same GlobalKey'. How can I avoid that, so that the user can add multiple items with the same name?
import 'package:flutter/material.dart';
class PlanOverview extends StatefulWidget {
const PlanOverview({Key key}) : super(key: key);
#override
_PlanOverviewState createState() => _PlanOverviewState();
}
class _PlanOverviewState extends State<PlanOverview> {
List<String> plans = ['Plan A', 'Plan B'];
void addPlan(String newPlan) {
setState(() {
plans.add(newPlan);
});
Navigator.of(context).pop();
}
void newEntry() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: TextField(
onSubmitted: addPlan,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
icon: Icon(Icons.text_snippet_outlined),
labelText: 'Name des Plans'),
),
);
});
}
void edit(int i) => showDialog(
context: context,
builder: (context) {
final plan = plans[i];
return AlertDialog(
content: TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
icon: Icon(Icons.text_snippet_outlined)),
initialValue: plan,
onFieldSubmitted: (_) => Navigator.of(context).pop(),
onChanged: (name) => setState(
() {
plans[i] = name;
},
)));
});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Trainingspläne'),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.only(bottomLeft: Radius.circular(10.0), bottomRight: Radius.circular(10.0)),
),
actions: [
IconButton(
onPressed: newEntry,
icon: Icon(Icons.add),
),
],
),
body: ReorderableListView.builder(
itemCount: plans.length,
onReorder: (oldi, newi) => setState(() {
final i = newi > oldi ? newi - 1 : newi;
final plan = plans.removeAt(oldi);
plans.insert(i, plan);
}),
itemBuilder: (context, i) {
final plan = plans[i];
return ListTile(
tileColor: Color.fromARGB(255, 34, 34, 34),
key: ValueKey(plan),
contentPadding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
title: Text(plans[i]),
onTap: () {
Navigator.push<Widget>(
context,
MaterialPageRoute(
builder: (context) =>
ExerciseTable(key: GlobalKey(), title: plans[i])));
},
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () {
edit(i);
}),
);
}),
);
}
}
When the user creates an element and adds it to the list, you can check the list for an element with the same name and if it exists, add its index to its name this way there cant be two elements with the same name.
You dont need to show the index part of the name to the user if you dont want to, its just for control purposes.
If you have a search bar where the user types the name of the element he wants to access you can use auto complete to show the elements tht contains what the user is typing.

When adding item to list in flutter, the item does not save in that list

I have a list of users which show in a dropdown in a form which is then submitted, the list is empty, I have made a function which allows users to type a "name" into a TextFormField and it then adds that name to the list, it then appears on the dropdown, but when the page is reloaded the list item has gone.
example:
void savePerson() {
String newperson = _newPersonController.text;
_persons.add(newperson);
}
The function to save string to list
List<String> _persons = [
];
The List
TextFormField(
controller: _newPersonController,
decoration: InputDecoration(
hintText: 'Add New Person',
prefixIcon: Icon(
Icons.local_hospital,
size: 30,
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
)),
The TextFormField where the user inserts the name to be added
FlatButton(
onPressed: () {
savePerson();
setState(() {
_newPersonController.clear();
});
},
child: Text('Add Person'))
Button code
Just to be clear, it ADDS it to the list/dropdown - that works, but my list doesn't seem to be able to save info to it.
I'm fairly new to flutter - sorry for anything obvious.
The problem maybe the logic of the dropdown, and add the setState() when you add the item to the people list
I use this code:
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _newPersonController =
new TextEditingController();
List<String> _persons = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: Column(
children: <Widget>[
DropdownButton(
items: List.generate(
_persons.length,
(i) => DropdownMenuItem(
child: Text(_persons[i]),
)),
onChanged: (_) {}),
TextFormField(
controller: _newPersonController,
decoration: InputDecoration(
hintText: 'Add New Person',
prefixIcon: Icon(
Icons.local_hospital,
size: 30,
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
)),
FlatButton(
onPressed: () {
savePerson();
setState(() {
_newPersonController.clear();
});
},
child: Text('Add Person'))
],
),
),
),
);
}
void savePerson() {
String newperson = _newPersonController.text;
setState(() {
_persons.add(newperson);
});
}
}
Probably can help you

Flutter how i can load list from other file?

I want to load a list from a file into a widget, I have several lists and a specific list with an id should be loaded.
This is my code:
main
class Cars extends StatefulWidget {
#override
_carsState createState() => _carsState();
}
class _carsState extends State<cars> {
List clist = [
{'id': 'l0', 'name': 'BMW'},
{'id': 'l1', 'name': 'Audi'},
];
#override
Widget build(BuildContext context) {
return Column(
children: clist.map((info) {
return Container(
margin: EdgeInsets.all(5),
child: SizedBox(
width: double.infinity,
child: RaisedButton(
padding: EdgeInsets.all(20),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0.0),
),
color: Colors.blue,
child: Text(
info['name'],
style: TextStyle(color: Colors.white),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cars(name: info['name'], id: info['id'],)),
);
},
),
),
);
}).toList(),
);
}
}
cars.dart
class Cars extends StatelessWidget {
final String name;
var id;
Cars({Key key, this.name, this.id}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(name),
backgroundColor: Colors.green,
centerTitle: true,
),
body: Column(
children: LISTFROMOTHERFILE.map((info) {
return Container(
margin: EdgeInsets.all(5),
child: SizedBox(
width: double.infinity,
child: Text(info['name'])
),
);
}).toList(),
));
}
}
list.dart
List l0 = [
{'name': 'Example', 'PS': '500'},
{'name': 'Example2', 'PS': '300'},
];
List l1 = [
{'name': 'Example', 'PS': '300'},
];
Now, if, for example, the ID 1 is transferred from the main, I would like the list l0 to be loaded!
How can I realize this or is there a better way to do it?
Better to make POJO class of your list
class ExampleList{
final String id;
final String name ;
final String PS;
/// implement [fromJson] and [toJson] method if needed
}
now whenever you need of it then just pass the whole object rather than passing strings.
you can use it like this
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cars(ExampleList:ExampleList)),
);

Synchronization of list view and detail view

I have an app with simple functionality. After authentication user see the page with ListView widget which is populated with help of StreamBuilder widget and BLoC. Click on ListView row opens details page with set of detail widgets (TextField. Now I need to change my GUI design for tables. As we have more space I decided to display details near the list view, i.e. when user clicks on ListView item no new page opened but details are displayed on the right side of ListView. I need the idea how to synchronize the detail view widget with selected item in list view widget. I figured out that I can use somehow ValueNotifier/ValueListenableBuilder but I can't gather my thoughts together. I need some ideas, please.
please use this package responsive_scaffold https://pub.dev/packages/responsive_scaffold
On mobile it shows a list and pushes to details and on tablet it shows the List and the selected item.
example code
import 'package:flutter/material.dart';
import 'package:responsive_scaffold/responsive_scaffold.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ResponsiveListScaffold.builder(
scaffoldKey: _scaffoldKey,
detailBuilder: (BuildContext context, int index, bool tablet) {
return DetailsScreen(
// appBar: AppBar(
// elevation: 0.0,
// title: Text("Details"),
// actions: [
// IconButton(
// icon: Icon(Icons.share),
// onPressed: () {},
// ),
// IconButton(
// icon: Icon(Icons.delete),
// onPressed: () {
// if (!tablet) Navigator.of(context).pop();
// },
// ),
// ],
// ),
body: Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text("Details"),
automaticallyImplyLeading: !tablet,
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
if (!tablet) Navigator.of(context).pop();
},
),
],
),
bottomNavigationBar: BottomAppBar(
elevation: 0.0,
child: Container(
child: IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
),
),
body: Container(
child: Center(
child: Text("Item: $index"),
),
),
),
);
},
nullItems: Center(child: CircularProgressIndicator()),
emptyItems: Center(child: Text("No Items Found")),
slivers: <Widget>[
SliverAppBar(
title: Text("App Bar"),
),
],
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Text(index.toString()),
);
},
bottomNavigationBar: BottomAppBar(
elevation: 0.0,
child: Container(
child: IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text("Snackbar!"),
));
},
),
),
);
}
}