Related
This question already has answers here:
ListView does not refresh whereas attached list does (Flutter)
(2 answers)
Closed 4 years ago.
I'm trying to create an app where I am able to get data from Cloud Firestore and create multiple custom widgets with the data.
The custom widget is eventCardWidget
import 'package:flutter/material.dart';
import 'package:do_and_stuff/settings/theme.dart';
class EventCardWidget extends StatelessWidget {
EventCardWidget(this.eventImage, this.eventTitle, this.eventDescription,
this.eventAddress, this.eventDate, this.eventTime, this.peopleRequired);
String eventTitle;
String eventAddress;
String eventDate;
String eventImage;
String eventTime;
String eventDescription;
int peopleRequired;
#override
Widget build(BuildContext context) {
return Material(
child: GestureDetector(
child: InkWell(
splashColor: ThemeSettings.CardInkwell,
onTap: () {},
child: Card(
elevation: 1.0,
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 14.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(right: 19.0),
width: 100.0,
height: 100.0,
child: Image.asset(this.eventImage, scale: .5),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Container(
margin: const EdgeInsets.only(
top: 12.0, bottom: 10.0),
child: Text(
eventTitle,
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
),
Container(
margin: const EdgeInsets.only(right: 10.0),
child: Text(
this.eventAddress,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Colors.grey[600]),
),
),
],
),
Container(
margin: const EdgeInsets.only(right: 10.0),
child: Text(
this.eventDescription,
style: TextStyle(
fontSize: 16.0,
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
),
Container(
padding: EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
margin: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
this.eventDate,
style: TextStyle(
color: Colors.grey[500],
fontSize: 11.0,
),
),
Container(
margin: const EdgeInsets.only(right: 10.0),
child: Text(peopleRequired.toString())),
],
),
),
],
),
),
],
),
),
),
),
);
}
}
Now, above my Widget build(BuildContext context) {
I have
List<Widget> cards = [];
and then within the Widget build(BuildContext context) { I have children: cards,
So at this point, this page would open up with cards being initialized empty.
But, I now have
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final List results = await db.getEvent(
DateFormat("y-MM-dd").format(DateTime.now()),
DateFormat("y-MM-dd").format(DateTime.now().add(Duration(days: 20))),
2,
);
for (DocumentSnapshot result in results) {
cards.add(EventCardWidget(
"assets/flutter-icon.png",
result.data.values
.toList()[result.data.keys.toList().indexOf("name")],
result.data.values
.toList()[result.data.keys.toList().indexOf("description")],
"1 mi",
"2018-10-29",
// result.data.values
// .toList()[result.data.keys.toList().indexOf("eventDate")],
"Time",
result.data.values
.toList()[result.data.keys.toList().indexOf("num")],
));
setState(() {
return cards;
});
}
});
}
Now, in Android Studio, I am able to see that cards has more elements when I set breakpoints, but nothing updates on the screen.
Now what's weird, is that when I do something like
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final List results = await db.getEvent(
DateFormat("y-MM-dd").format(DateTime.now()),
DateFormat("y-MM-dd").format(DateTime.now().add(Duration(days: 20))),
2,
);
for (DocumentSnapshot result in results) {
setState(() {
return cards = List.generate(
3,
(i) => new EventCardWidget(
"assets/flutter-icon.png",
"Title",
"Description",
"12 mi",
"2018-10-29",
"Time",
5),
growable: true,
);
});
}
});
}
Then the text on the screen updates.
Any ideas?
This is not a duplicate because I have tried the solution Here and it still does not work
for (DocumentSnapshot result in results) {
setState(() {
cards = List.from(cards)
..add(EventCardWidget(
"assets/flutter-icon.png",
result.data.values
.toList()[result.data.keys.toList().indexOf("name")],
result.data.values
.toList()[result.data.keys.toList().indexOf("description")],
"1 mi",
"2018-10-29",
result.data.values.toList()[
result.data.keys.toList().indexOf("peopleRequired")],
));
});
}
Your code started working for me when I did this
for (DocumentSnapshot result in results) {
cards = List.from(cards)
..add(EventCardWidget(
"assets/flutter-icon.png",
result.data.values
.toList()[result.data.keys.toList().indexOf("name")],
result.data.values
.toList()[result.data.keys.toList().indexOf("description")],
"1 mi",
"2018-10-29",
"8:00pm",
result.data.values
.toList()[result.data.keys.toList().indexOf("peopleRequired")],
));
setState(() {
this.cards = cards;
});
}
**Hello, I am developing an app in which the user should enter the integer values.according to that values we should display those number of text fields..
for Example:
1) enter total number of subject=10;
2) click on the button;
3) After button is clicked should display 10 text fields;
4) I have no idea what to do so if you know then help me plz.**
import 'package:flutter/material.dart';
class imcaaddsubject extends StatefulWidget {
#override
_imcaaddsubjectState createState() => _imcaaddsubjectState();
}
class _imcaaddsubjectState extends State<imcaaddsubject> {
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(5),
child: Card(
child: ListView(
padding: EdgeInsets.all(10),
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10),
),
new TextField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(style: BorderStyle.solid)),
labelText: "NUMBER OF SUBJECTS",
hintText: "Enter number of subjects",
),keyboardType: TextInputType.number,
),
Padding(
padding: EdgeInsets.only(top: 15),
),
new RaisedButton(
child: Text(
"OK",
style:
TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
color: Colors.cyan,
onPressed: () {},
)
],
),
),
);
}
}
You can try like this :
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
int numberOfSubjects = 0;
Widget subjectsBuilder(int numberOfSubjects) {
if (numberOfSubjects > 0) {
return ListView.builder(
itemBuilder: (BuildContext context, numberOfSubjects) {
return TextField(
decoration: InputDecoration(hintText: "enter a text"),
);
},
itemCount: numberOfSubjects,
);
} else {
return SizedBox();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Card(
child: ListView(
padding: EdgeInsets.all(10),
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10),
),
new TextField(
onSubmitted: (String value) {
setState(() {
numberOfSubjects = int.parse(value);
});
},
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(style: BorderStyle.solid)),
labelText: "NUMBER OF SUBJECTS",
hintText: "Enter number of subjects",
),
keyboardType: TextInputType.number,
),
Padding(
padding: EdgeInsets.only(top: 15),
),
],
),
),
),
),
Expanded(
child: subjectsBuilder(numberOfSubjects),
)
]),
);
}
}
this code will display a number of text fields according to user input below the first text field , of course you can render it in a new page .. also you don't have to use a button , it's enough to user submit text .
Im creating a login form in flutter and I want to use snackbar to show a message when login fails. I read this documentation and if i have this code should works
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
Scaffold.of(context).showSnackBar(snackBar);
But return this error
Scaffold.of() called with a context that does not contain a Scaffold.
My login.dart all code
import 'package:flutter/material.dart';
import 'package:fluttercrud/screens/home_page.dart';
class LoginPage extends StatelessWidget {
static String tag = 'login-page';
#override
Widget build(BuildContext context) {
final logo = Hero(
tag: 'hero',
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: 48.0,
child: Image.asset('assets/logo.png'),
),
);
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: 'Usuario',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
);
final password = TextFormField(
autofocus: false,
obscureText: true,
decoration: InputDecoration(
hintText: 'Contraseña',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: () {
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
Scaffold.of(context).showSnackBar(snackBar);
//Navigator.of(context).pushNamed(HomePage.tag);
},
color: Colors.blue[300],
child: Text('Entrar', style: TextStyle(color: Colors.white)),
),
),
);
final forgotLabel = FlatButton(
child: Text(
'¿Contraseña olvidada?',
style: TextStyle(color: Colors.black),
),
onPressed: () {},
);
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: <Widget>[
logo,
SizedBox(height: 48.0),
email,
SizedBox(height: 8.0),
password,
SizedBox(height: 24.0),
loginButton,
forgotLabel
],
),
),
);
}
}
The scaffold return a error but i don´t know how can i fix this without rewrite all code.
So the question is: How can i to show the snackbar when login fails and avoid this error? And why this error appears?
UPDATED
void initState() {
super.initState();
final snackBar = SnackBar(
content: Text(
'Usuario/Contraseña incorrecto',
textAlign: TextAlign.center,
));
Scaffold.of(context).showSnackBar(snackBar);
seriesList = _createSampleData();
animate = false;
}
And how can i show snackbar when init page?
This is because you are using the context of the widget that creates the Scaffold (the parent context), not the context of the Scaffold itself. Thus the error.
You can fix the error either by creating a method builder that will receive the correct context:
Widget _buildLoginButton(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: () {
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
Scaffold.of(context).showSnackBar(snackBar);
},
color: Colors.blue[300],
child: Text('Entrar', style: TextStyle(color: Colors.white)),
),
),
);
}
And refactor the page to use the builder method you've just created:
Scaffold(
appBar: AppBar(
title: Text('My Page'),
),
body: Builder(
builder: (context) =>
Column(
children: [
.....
_buildLoginButton(context),
.....
]
),
),
),
);
Or just extract the login button to its own Widget, without changing any other of your code, and it will receive the proper context.
class LoginButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: () {
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
Scaffold.of(context).showSnackBar(snackBar);
},
color: Colors.blue[300],
child: Text('Entrar', style: TextStyle(color: Colors.white)),
),
),
);
}
}
TextFormField is not working properly, its blinking continuously and it doesn't allow me to write anything, as I tap on the TextFormField my keyboard appears for a second and disappear instantly. I am confused what wrong I have done with my code, I've matched my code with previous working code, but still getting this behaviour .
Here is my code.
class ComingSoonState extends State<ComingSoon> {
String language;
TextEditingController _textEdititingController ;
#override
void initState() {
_textEdititingController = new TextEditingController(); //Initialised TextEditingController
super.initState();
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final Size size = MediaQuery.of(context).size;
final formData = new Form(
key: widget._formKey,
child: new Container(
padding: const EdgeInsets.only(
left: 35.0,
right: 35.0),
child: new Column(
children: <Widget>[
new Theme(
data: theme.copyWith(primaryColor: Colors.black54),
child: new TextFormField(
controller: _textEdititingController, //ADDED CONTROLLER HERE
style: const TextStyle(color: Colors.black54),
decoration: new InputDecoration(
labelText: 'Amount',
labelStyle: const TextStyle(color: Colors.black54)
),
// validator: this._validateEmail,
validator: (val) {
return val.isEmpty
? "Please enter amount"
: null;
},
onSaved: (String value) {
// this._data.email = value;
this.language = value;
}
),
),
],
),
),
);
return Scaffold(
appBar: new AppBar(
leading: null,
title: const Text('Send Money', style: const TextStyle(
color: Colors.white
),
),
),
body: new Container(
color: Colors.grey[300],
child: new ListView(
children: <Widget>[
new Container(
child: new Column(
children: <Widget>[
new Container(
height: 60.0 ,
padding: const EdgeInsets.all(5.0),
child: new Card(
child: new Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: new Text("Available balance in wallet", style:
new TextStyle(color: Colors.black54,
fontSize: 16.0
),),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: new Text("123 KSH", style:
new TextStyle(color: Colors.blueAccent,
fontSize: 16.0
),),
),
],
),
),
) ,
new Container(
//height: 300.0,
padding: const EdgeInsets.all(5.0),
child: new Card(
child: new Container(
child: new Center(
child: new Column(
children: <Widget>[
formData
],
),
),
),
),
)
],
)
),
],
),
),
);
}
}
I added a floating action button that presents a dialog that will show what you entered into the TextField (using the controller). I'm not sure what form key you were passing in before but making the GlobalKey instance a member variable eliminates the keyboard present/dismiss issue.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String language;
TextEditingController _textEditingController;
final _formKey = GlobalKey<FormState>();
#override
void initState() {
_textEditingController =
TextEditingController(); //Initialised TextEditingController
super.initState();
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final Size size = MediaQuery.of(context).size;
final formData = Form(
key: _formKey,
child: Container(
padding: const EdgeInsets.only(left: 35.0, right: 35.0),
child: Column(
children: <Widget>[
Theme(
data: theme.copyWith(primaryColor: Colors.black54),
child: TextFormField(
controller: _textEditingController,
//ADDED CONTROLLER HERE
style: const TextStyle(color: Colors.black54),
decoration: InputDecoration(
labelText: 'Amount',
labelStyle: const TextStyle(color: Colors.black54)),
// validator: this._validateEmail,
validator: (val) {
return val.isEmpty ? "Please enter amount" : null;
},
onSaved: (String value) {
// this._data.email = value;
language = value;
}),
),
],
),
),
);
return Scaffold(
appBar: AppBar(
leading: null,
title: const Text(
'Send Money',
style: const TextStyle(color: Colors.white),
),
),
body: Container(
color: Colors.grey[300],
child: ListView(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Container(
height: 60.0,
padding: const EdgeInsets.all(5.0),
child: Card(
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
"Available balance in wallet",
style: TextStyle(
color: Colors.black54, fontSize: 16.0),
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
"123 KSH",
style: TextStyle(
color: Colors.blueAccent, fontSize: 16.0),
),
),
],
),
),
),
Container(
//height: 300.0,
padding: const EdgeInsets.all(5.0),
child: Card(
child: Container(
child: Center(
child: Column(
children: <Widget>[formData],
),
),
),
),
)
],
)),
],
),
),
floatingActionButton: FloatingActionButton(
// When the user presses the button, show an alert dialog with the
// text the user has typed into our text field.
onPressed: () {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
// Retrieve the text the user has typed in using our
// TextEditingController
content: Text(_textEditingController.text),
);
},
);
},
tooltip: 'Show me the value!',
child: Icon(Icons.text_fields),
),
);
}
}
I want to create a widget that will build describe in this photo
I already created the meter bar but I still don't know how to add numbers from start to end of bar and a arrow in bottom where place what points you have and with same color above of it
child: Row(children: <Widget>[
Column(children: <Widget>[
Padding(
padding: EdgeInsets.all(5.0),
child: Container(
decoration: new BoxDecoration(
border: new Border(right: BorderSide(color: Colors.black))
),
child: Column(
children: <Widget>[
Text('Points'),
Text('38'),
],
),
),
),
],),
// green bar
Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(right:10.0),
child: Container(
width:ratewidth,
decoration: new BoxDecoration(
border: new Border(bottom: BorderSide(color: Colors.green, width: 5.0))
),
),
)
],),
//yellow bar
Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(right:10.0),
child: Container(
width:ratewidth,
decoration: new BoxDecoration(
border: new Border(bottom: BorderSide(color: Colors.yellow, width: 5.0))
),
),
),
],),
...
],)
With a combination of Row, Column and Align it can be done in a few lines.
The hardest part is actually the triangle. Usually, you'll want to use CustomPainter for the triangle, but I was lazy here. So I combined translation, rotation, and a clip.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHome(),
);
}
}
class MyHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: ScoreMeter(
score: 1,
),
)
],
),
);
}
}
class ScoreMeter extends StatelessWidget {
final int score;
ScoreMeter(
{
this.score,
Key key})
: super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
height: 100.0,
child: Row(
children: <Widget>[
Expanded(
child: ScoreMeterItem(
score: score, color: Colors.green, minRange: 0, maxRange: 50),
),
Expanded(
child: ScoreMeterItem(
score: score,
color: Colors.yellow,
minRange: 51,
maxRange: 100),
),
Expanded(
child: ScoreMeterItem(
score: score,
color: Colors.orange,
minRange: 101,
maxRange: 150),
),
Expanded(
child: ScoreMeterItem(
score: score, color: Colors.red, minRange: 151, maxRange: 200),
),
Expanded(
child: ScoreMeterItem(
score: score,
color: Colors.purple,
minRange: 201,
maxRange: 250),
),
Expanded(
child: ScoreMeterItem(
score: score,
color: Colors.brown,
minRange: 251,
maxRange: 300),
),
],
),
);
}
}
class ScoreMeterItem extends StatelessWidget {
/// Hello World
final int score;
final Color color;
final int minRange;
final int maxRange;
ScoreMeterItem(
{this.score,
this.color = Colors.grey,
#required this.minRange,
#required this.maxRange,
Key key})
: assert(minRange != null),
assert(maxRange != null),
super(key: key);
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(minRange.toString(), style: theme.textTheme.caption),
Text(maxRange.toString(), style: theme.textTheme.caption),
],
),
ScoreMeterBar(color: color),
score >= minRange && score <= maxRange
? SizedBox(
height: 10.0,
child: Align(
alignment: Alignment(
(score - minRange) / (maxRange - minRange) * 2 - 1,
0.0),
child: Arrow(color: color),
),
)
: SizedBox()
],
),
);
}
}
class Arrow extends StatelessWidget {
final Color color;
Arrow({this.color});
#override
Widget build(BuildContext context) {
return SizedBox(
height: 5.0,
width: 10.0,
child: ClipRect(
child: OverflowBox(
maxWidth: 10.0,
maxHeight: 10.0,
child: Align(
alignment: Alignment.topCenter,
child: Transform.translate(
offset: Offset(.0, 5.0),
child: Transform.rotate(
angle: pi / 4,
child: Container(
width: 10.0,
height: 10.0,
color: color,
),
),
),
),
),
),
);
}
}
class ScoreMeterBar extends StatelessWidget {
final Color color;
ScoreMeterBar({this.color = Colors.grey, Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 8.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(4.0),
),
color: color,
),
);
}
}