I want to have a normal questionare type of thing.
As soon as the first question gets answered it should go to next question.
But there was an error as 'type 'Null' is not a subtype of type 'List' in type cast' when I used .map().
The .map() and spread operator used to function in previous versions of flutter but now they are not.Can anyone please give a solution for this?
this is the following code-main.dart
class MyAppState extends State<MyApp> {
int qindex = 0;
void answeQues() {
setState(() {
qindex = qindex + 1;
});
print(qindex);
}
#override
Widget build(BuildContext context) {
var questions = [
{
'questionText': 'what\'s your favourite color?',
'answers': ['R', 'G', 'B', 'Y']
},
{
'questionText': 'what\'s your favourite animal?',
' answers': ['Rabbit', 'Giraffe', 'Bear', 'Yax']
},
{
'questionText': 'what\'s your favourite sport?',
'answers': ['Rugby', 'Cricket', 'Basketball', 'Football']
},
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My first App'),
),
body: Column(
children: [
Questions(
questions[qindex]['questionText'].toString(),
),
...(questions[qindex]['answers'] as List<String>).map((answer) {
return Answers(answeQues, answer);
}).toList()
// questions[qindex]['answers'].entries.map((answer) {
// return Answers(answeQues, answer);
// }).toList()
],
),
),
);
}
}
this is my answers.dart file
import 'package:flutter/material.dart';
class Answers extends StatelessWidget {
final Function selectHandler;
final String answerText;
Answers(this.selectHandler, this.answerText);
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: EdgeInsets.all(10),
child: RaisedButton(
color: Colors.blue,
child: Text(answerText),
onPressed: () {
selectHandler();
},
),
);
}
}
Error:-
type 'Null' is not a subtype of type 'List' in type cast.
For your second question, you have space at the beginning of the key name (' answers'), that causes the problem:
var questions = [
...
{
'questionText': 'what\'s your favourite animal?',
' answers': ['Rabbit', 'Giraffe', 'Bear', 'Yax']
},
...
];
There is nothing wrong about .map() and spread operators, they are still used in Flutter.
Related
I'm trying to set quotes from list to Text widget but i am facing this problem
The argument type 'List<Iterable>' can't be assigned to the parameter type 'List'.
this is my code
import 'package:flutter/material.dart';
void main() {
runApp(myApp());
}
class myApp extends StatefulWidget {
#override
_myAppState createState() => _myAppState();
}
class _myAppState extends State<myApp> {
List<String> quotesList = [
"The secret of getting ahead is getting started",
"Only the paranoid survive",
"It’s hard to beat a person who never gives up.",
"Never Had luck never needed it"
];
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.black38,
title: Text("Quotes"),
),
body: Column(
children: [quotesList.map((e) => Text(e))].toList(),
),
),
);
}
}
You don't need to wrap the list with '[' and ']'
Column(
children: quotesList.map((e) => Text(e)).toList(),
),
And if you want to add more widgets, you can use like this
Column(
children: quotesList.map<Widget>((e) => Text(e)).toList()
..addAll([
Container() //You can use addAll method and add some juicy widgets
]),
),
Here is another (easy) approach.
Add this function to your current class -
List<Widget> getTextWidgets() {
List<Widget> _widgets = [];
for(int i=0;i<quotesList.length;i++) {
_widgets.add(
Text(quotesList[i])
);
}
return _widgets;
}
And simply call it like -
body: Column(
children: getTextWidgets(),
),
Remove [] from the quotesList -
quotesList.map((e) => Text(e)).toList(),
This might fix your issue -
import 'package:flutter/material.dart';
void main() {
runApp(myApp());
}
class myApp extends StatefulWidget {
#override
_myAppState createState() => _myAppState();
}
class _myAppState extends State<myApp> {
List<String> quotesList = [
"The secret of getting ahead is getting started",
"Only the paranoid survive",
"It’s hard to beat a person who never gives up.",
"Never Had luck never needed it"
];
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.black38,
title: Text("Quotes"),
),
body: Column(
children: quotesList.map((e) => Text(e)).toList(),
),
),
);
}
}
To answer your question, you need to remove the [ and ], to look like this
quotesList.map((e) => Text(e)).toList()
If you want to add more widgets, you can use the spread operator
Column(
children: <Widget>[
// you can add more widgets here
...quotesList.map((e) => Text(e)),
// you can add more widgets here too
],
)
I have the following code where I generate a list of items(data is taken from Firebase). I would like to implement a functionality to remove items but I don't know how to access the list and how to remove items:
class _MyOfferState extends State<MyOffer> {
List<Widget> items = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
...
body: SingleChildScrollView(
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('Offers')
builder: (BuildContext context, snapshot) {
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(name, category, context,...));
});
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
},
),
}
}
This is a dynamic class where I have GestureDetector. The item should be deleted when a user clicks on the it.
dynamic offer(name, category, context,) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: () {
// remove item should be here
},
);
}
Removing the offer from within itself is not the best practice but you can accomplish it in a number of ways. The first I can think of is to pass a function that removes it when creating the offer like this:
items.add(offer(name, category, context,..., () {
setState(() {
FirebaseFirestore.instance
.collection('Offers')
.doc(element['id'])
.delete();
items.remoev(index);
});
}));
You'll need to create the index beforehand and increase it each time but I don't recommend doing it.
The way I would done do this is change the offer to be:
dynamic offer(name, category, context,) {
return Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
);
}
And when creating the offer wrap it in the GestureDetector like this:
items.add(GestureDetector(
child: offer(name, category, context,...)),
onTap: () {
setState(() {
FirebaseFirestore.instance
.collection('Offers')
.doc(element['id'])
.delete();
items.remoev(index);
});
},
);
You'll have to do the same thing with the index but I consider it a better approach since the child has no power over the parent and can't change its state which is a good practice.
you need to pass index of item and delete by index:
int index = 0;
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(index, name, category, context,...));
index++;
});
Widget offer(int index, string name, string category, BuildContext context,) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: () {
// remove item should be here
items.removeAt(index);
setState((){});
},
);
}
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
Your list is getting build by Stream data the one you provided to your StreamBuilder, do create new list you need to change Stream value, I suggest to keep FirebaseFirestore.instance.collection('Offers') instance in a stream and modify the stream.
class _MyOfferState extends State<MyOffer> {
List<Widget> items = [];
StreamController _controller = StreamController();
#override
void initState() {
super.initState();
_controller.addStream( FirebaseFirestore.instance
.collection('Offers').snapshots());
}
// dont forgot to close stream
#override
void dispose() {
_controller.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
...
body: SingleChildScrollView(
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: _controller.stream,
builder: (BuildContext context, snapshot) {
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(name, category, context,(){
// remove function is here
snapshot.data.docs.removeWhere((e) => e.id == element.id);
_controller.add(snapshot.data);
});
});
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
},
),
}
}
Also pass onTap to your widget function
dynamic offer(name, category, context, onTap) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: onTap,
);
}
Im making a list of radio buttons. But cant figure a way to map them. The current method making one by one which is too much and with 10+ radio buttons this is taking up hundreds of lines of code.
enum SingingCharacter {char1, char2, char3, char4}
class _HomeScreenState extends State<HomeScreen> {
SingingCharacter _character = SingingCharacter.char1;
final List myList= ['One','Two','Thre' ];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Container(
child: Column(children: <Widget>[
RadioListTile<SingingCharacter>(
title: Text('${myList[0]}'),
value: SingingCharacter.char1,
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
),
RadioListTile<SingingCharacter>(
title: Text('${myList[1]}'),
value: SingingCharacter.char2,
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
)
....
]),
));
}
}
Any method to loop through this and show in children?
Thanks
You could change your List to a Map and then use this to map your enum values to Widgets. Like this (disclaimer: Code not tested, but something like this should be possible):
enum SingingCharacter {char1, char2, char3}
class _HomeScreenState extends State<HomeScreen> {
SingingCharacter _character = SingingCharacter.char1;
final Map<SingingCharacter, String> radioMap = {SingingCharacter.char1: 'One', SingingCharacter.char2: 'Two', SingingCharacter.char3: 'Three'};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Container(
child: Column(
children: _generateRadioButtons()
),
)
);
}
List<Widget> _generateRadioButtons() {
return SingingCharacter.values.map((char) {
return RadioListTile<SingingCharacter>(
title: Text('${radioMap[char]}'),
value: char
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
);
}).toList();
}
}
You can take advantage of the spread operator and unwrap directly a for loop on your Column.
final List myList= ['One','Two','Thre' ];
return Column(children: [
for (int i = 0; i < myList.length; i++)
RadioListTile<SingingCharacter>(
title: Text(myList[i]),
value: SingingCharacter.values[i],
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
),
]);
I want to implement a searchbar in my flutter application. I have to go through a listview out of ListTiles. Here I want to check if the title of the listtile contains the letters in the search field. Is this possible with a List?
It does not have to be with the title. It could be something else with what I can identify the Tile. But please, not the index, the user would not know it.
Is a List the right widget or do I have to use something else to implement a search Engine in my Application
Rather than using a 3rd party package, you can use native showSearch() function :
showSearch(context: context, delegate: ListSearchDelegate());
And then a class extending SearchDelegate:
class ListSearchDelegate extends SearchDelegate{
ListSearchDelegate({Key key,}): super() ;
List<String> listItems = <String>['One', 'Two', 'Three', 'Four', 'Five'] ;
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
List<String> subList ;
subList = query != '' ? listItems.where((item) => item.contains(query)).toList() :
listItems ;
return ListView.builder(
itemCount: subList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(subList[index]),
);
}
);
}
#override
Widget buildSuggestions(BuildContext context) {
return Container();
}
}
Try https://pub.dev/packages/flutter_search_panel
List<SearchItem<int>> data = [
SearchItem(0, 'This'),
SearchItem(1, 'is'),
SearchItem(2, 'a'),
SearchItem(3, 'test'),
SearchItem(4, '.'),
];
FlutterSearchPanel<int>(
padding: EdgeInsets.all(10.0),
selected: 3,
title: 'Demo Search Page',
data: data,
icon: new Icon(Icons.check_circle, color: Colors.white),
color: Colors.blue,
textStyle: new TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20.0, decorationStyle: TextDecorationStyle.dotted),
onChanged: (int value) {
print(value);
},
),
I am using Firebase realtime database to retrieve information and then present it in a scrollable DataTable.
To make the DataTable scrollable, I wrapped it up in a ListView, as per the comment of this post:
DataTable - make scrollable, set background colour and fix/freeze header row and first column
This is my code:
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'cprdata.dart';
import 'dart:convert';
class CprAnalysis extends StatefulWidget {
#override
CPRState createState() => CPRState();
}
class CPRState extends State<CprAnalysis> {
///var cpr = UpdateData.getData();
List<FilterData> acData;
List<FilterData> getData() {
var cpr = <FilterData>[];
DatabaseReference cprData = FirebaseDatabase.instance.reference();
cprData.reference().once().then((DataSnapshot snap) {
var d = snap.value;
final jsonE = json.encode(d);
final jsonResponse = json.decode(jsonE);
MyDataList zz = new MyDataList.fromJson(jsonResponse);
zz.myList.forEach((data) {
cpr.add(FilterData(sYMBOL: data.SYMBOL, fORECAST: data.FORECAST));
}
);
},
);
print(cpr);
return cpr;
}
#override
void initState() {
super.initState();
acData = getData();
}
Widget bodydata() => Expanded(
child: ListView(
///shrinkWrap: true,
padding: const EdgeInsets.all(8.0),
childern: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: <DataColumn>[
DataColumn(
label: Text("Symbol"),
numeric: false,
),
DataColumn(
label: Text("Forecast"),
numeric: false,
),
],
rows: acData.map((data) =>
DataRow(
cells: [
DataCell(
Text(data.sYMBOL),
showEditIcon: false,
placeholder: false,
),
DataCell(
Text(data.fORECAST),
showEditIcon: false,
placeholder: false,
)
],
),
)
.toList()
),
),
]
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("CPR Analysis"),
),
body: Container(
child: bodydata(),
),
);
}
}
class FilterData {
String sYMBOL, fORECAST;
FilterData({
this.sYMBOL,
this.fORECAST});
}
Expected output: Scrollable DataTable.
Actual output: error: The named parameter 'childern' isn't defined under ListView()
You misspelled children as childern in your code.
Make your ListView code as -
ListView(
children: <Widget> [
//Your remaining code
]
),