How to access a method in root class from a state class in flutter - callback

I have three classes in my dart file:
CardMgmt which is my root class and is stateless,
ExpandableListView which is stateful and _ExpandableListViewState which is the state class of its parent (ExpandableListView).
I need to access a method in CardMgmt from _ExpandableListViewState.
This is my code:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/home_page.dart';
import 'package:flutter_app/model/BankCard.dart';
class CardMgmt extends StatelessWidget {
Function callback;
//final VoidCallback callback;
CardMgmt(this.callback);
callBack(int n){
callback(n);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xFF421000),
appBar: new PreferredSize(child: new Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new GestureDetector(onTap: (){
_callBack(11);
}, child:
Icon(Icons.add_circle_outline, size: 50, color: Colors.white)),
new Icon(Icons.autorenew, size:50, color: Colors.white)
]), preferredSize: Size.fromHeight(40)),
body: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ExpandableListView(title: " کارت $index");
},
itemCount: 10,
)
);
}
}
class ExpandableListView extends StatefulWidget {
final String title;
const ExpandableListView({Key key, this.title}) : super(key: key);
#override
_ExpandableListViewState createState() => new _ExpandableListViewState();
}
class _ExpandableListViewState extends State<ExpandableListView> {
bool expandFlag = false;
final List<BankCard> items = new List();
void _showDialog(BuildContext con) {
showDialog(
context: con,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(32.0))),
title: Center(child: Text('هشدار')),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
child: Text(
"آیا می خواهید کارت را حذف کنید؟",
textAlign: TextAlign.start,
style: TextStyle(
color: Colors.blue,
fontSize: 18,
fontWeight: FontWeight.w700),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
child: Text('بله', ),
onPressed: () {
Navigator.of(context).pop();
}),
FlatButton(
child: Text('خیر'),
onPressed: () {
Navigator.of(context).pop();
})
])
],
),
);
});
}
#override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.symmetric(vertical: 1.0),
child: new Column(
children: <Widget>[
new GestureDetector(
onTap: () {
setState(() {
expandFlag = !expandFlag;
});
},
child: new Container(
//this is fixed container
height: 100,
width: 290,
margin: EdgeInsets.only(top: 15),
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(Radius.circular(12.0)),
color: Colors.white,
),
padding: new EdgeInsets.symmetric(horizontal: 5.0),
child: new Row(textDirection: TextDirection.ltr,
children: <Widget>[
Expanded(
child: new Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('کارت سپردم',
style: new TextStyle(
fontSize: 17.0,
fontWeight: FontWeight.bold)),
new Text('6104-6587-5841-9955',
style: new TextStyle(
fontSize: 17.0,
fontWeight: FontWeight.bold)),
new Text('1254000 ريال'),
]))),
new Container(
//width: 25,
//color: Colors.red,
//margin: EdgeInsets.all(0.0),
alignment: Alignment.centerRight,
child: new Image.asset(
'assets/4.0x/maskanlogoxxxhdpi.png',
width: 40))
]))),
new ExpandableContainer(
//this is expandable container
expanded: expandFlag,
child: new SingleChildScrollView(
child: new Container(
height: 200,
width: 300,
margin: EdgeInsets.only(top: 0.5, bottom: 5),
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(Radius.circular(20.0)),
color: Colors.white,
),
child: new Row(textDirection: TextDirection.ltr,
children: <Widget>[
Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.rtl,
children: <Widget>[
new FlatButton.icon(
onPressed: () {
_onTapItem(context);
},
icon: new Icon(Icons.do_not_disturb_alt),
label: new Text('غیرفعال کردن'),
padding: EdgeInsets.only(left: 0),
),
new FlatButton.icon(
onPressed: () {
_onTapItem(context);
},
icon: new Icon(Icons.clear),
label: new Text('مسدود نمودن'),
padding: EdgeInsets.only(left: 0),
),
new FlatButton.icon(
onPressed: () {
_onTapItem(context);
},
icon: new Icon(Icons.refresh),
label: new Text('فعال سازی'),
padding: EdgeInsets.only(left: 0),
)
])),
// Expanded(child:
new Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.rtl,
children: <Widget>[
new FlatButton.icon(
onPressed: () {
_showDialog(context);
},
icon: new Icon(Icons.delete),
label: new Text('حذف کارت')),
new FlatButton.icon(
onPressed: () {
//Here I need to call _callBack()
},
icon: new Icon(Icons.edit),
label: new Text('ویرایش کارت')),
new FlatButton.icon(
onPressed: () {
_onTapItem(context);
},
icon: new Icon(Icons.update),
label: new Text('بروزرسانی سرویس ها')),
new FlatButton.icon(
onPressed: () {
_onTapItem(context);
},
icon: new Icon(Icons.check),
label: new Text('تغییر حساب پیشفرض')),
])
// )
]))
)
)
]
)
);
}
void _onTapItem(BuildContext context) {
Scaffold.of(context)
.showSnackBar(new SnackBar(content: new Text('item clicked')));
}
}
I need to call callBack(int n) where I have commented.

I solved the problem by passing Function callback to _ExpandableListViewState as an attribute of the class:
final String title;
final Function cbk;
const ExpandableListView({Key key, this.title, this.cbk}) : super(key: key);
And use it the onTap() where I needed to do callback:
widget.cbk(12);
And it Worked. :-)

Define the _callBack method as static :
static void _callBack(int n){
callback(n);
}
then on your onPressed method :
CardMgmt._callBack(8);

Related

How to update a field even if it is not inside the build Widget?

I have 2 variables that can be updated if I pressed a button. _tempQuan1 is not getting updated (immediately) since it is not in the build Widget. On the other hand, _tempQuan2 gets the updated for every button press. Is there a way so that I can get the _tempQuan1 to work same as _tempQuan2?
Note: I have tried to remove all other codes until I found out about the information above.
Edit: I have also tried to make it as a stateless widget and use Getx and make an observable variable but I still unable to do it.
import 'package:flutter/material.dart';
import 'package:awesome_dialog/awesome_dialog.dart';
class ShoppingWidget extends StatefulWidget {
State<StatefulWidget> createState() => ShoppingState();
}
class ShoppingState extends State<ShoppingWidget> {
int _tempQuan1 = 1;
int _tempQuan2 = 1;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
showBuyPopup() async {
AwesomeDialog(
context: context,
dialogType: DialogType.NO_HEADER,
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: <Widget>[
Container(
width: 32.0,
height: 25.0,
child: Text(
_tempQuan1.toString(),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Material(
child: InkWell(
splashColor: Theme.of(context).primaryColor,
onTap: () {
if (this.mounted) {
setState(() {
_tempQuan1++;
});
}
print('increase');
},
child: Container(
width: 35.0,
height: 32.0,
decoration: BoxDecoration(
color: Theme.of(context).primaryColorDark.withOpacity(0.9),
borderRadius: BorderRadius.circular(8.0),
),
child: Icon(
Icons.add,
color: Colors.white,
size: 18.0,
),
),
),
),
),
],
),
SizedBox(
height: 10.0,
),
],
),
),
buttonsTextStyle: Theme.of(context).textTheme.bodyText2,
showCloseIcon: false,
btnCancelOnPress: () {},
btnOkOnPress: () async {},
)..show();
}
#override
Widget build(BuildContext context) {
print('PATH: item card widget build');
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Text(
_tempQuan2.toString(),
),
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Material(
child: InkWell(
splashColor: Theme.of(context).primaryColor,
onTap: () {
if (this.mounted) {
setState(() {
_tempQuan2++;
});
}
print('increase');
},
child: Container(
width: 35.0,
height: 32.0,
decoration: BoxDecoration(
color: Theme.of(context).primaryColorDark.withOpacity(0.9),
borderRadius: BorderRadius.circular(8.0),
),
child: Icon(
Icons.add,
color: Colors.white,
size: 18.0,
),
),
),
),
),
],
),
Container(
child: ElevatedButton(
onPressed: () {
showBuyPopup();
},
child: Text(
'Button',
),
),
),
],
),
);
}
}
The easiest solution is to move the body of your dialog into it's own stateful widget.. ie something like
AwesomeDialog(
context: context,
body: MyAwesomeDialogBody(tempQuan: _tempQuan2),
).show()
And then have a stateful widget MyAwesomeDialogBody which basically does everything you had previously in the body.
You would also have to pass in some callback so the changes to tempQuan are communicated back to the parent widget..

Flutter - ImagePicker does not display the image selected

I am trying to use ImagePicker. When an image is selected, it is not displayed on the screen. Value seems to be null. Below, you will find the full source code. I have done some research, but I have not find what mistake I am doing. If you could point me in the right direction, it would be great and appreciated. Many thanks.
class CaptureV2 extends StatefulWidget {
CaptureV2({Key key}) : super(key: key);
#override
_CaptureV2State createState() => _CaptureV2State();
}
class _CaptureV2State extends State<CaptureV2> {
GlobalKey<FormState> _captureFormKey = GlobalKey<FormState>();
bool isOn = true;
String _valueTaskNameChanged = '';
String _valueTaskNameToValidate ='';
String _valueTaskNameSaved='';
File imageFile;
_openGallery(BuildContext context) async{
imageFile = await ImagePicker().getImage(source: ImageSource.gallery) as File;
this.setState(() {
});
}
_openCamera(BuildContext context) async {
imageFile = await ImagePicker().getImage(source: ImageSource.camera) as File;
this.setState(() {
});
}
Widget _showImageView(context){ //Even when I am selecting an image I always get null
if(imageFile ==null) {
return Text('No attachment');
}else{
return Image.file(imageFile, width: 200, height: 200,);
}
}
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
drawer: MyMenu(),
appBar: AppBar(
centerTitle: true,
title: Text('CAPTURE'),
actions: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(0,22,0,0),
child: Text("On/Off"),
),
Switch(
value: isOn,
onChanged: (value) {
setState(() {
isOn = value;
});
},
activeTrackColor: Colors.green,
activeColor: Colors.green,
),
],
),
//==================
body: isOn?
SingleChildScrollView(
child: Column(
// crossAxisAlignment: CrossAxisAlignment.end,
// mainAxisAlignment: MainAxisAlignment.end,
children: [
Form(
key: _captureFormKey,
child: Column(
// crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(8.0, 0.0, 15.0, 1.0),
child: TextFormField(
decoration: InputDecoration(hintText: "Task Name"),
maxLength: 100,
maxLines: 3,
onChanged: (valProjectName) => setState(() => _valueTaskNameChanged = valProjectName),
validator: (valProjectName) {
setState(() => _valueTaskNameToValidate = valProjectName);
return valProjectName.isEmpty? "Task name cannot be empty" : null;
},
onSaved: (valProjectName) => setState(() => _valueTaskNameSaved = valProjectName),
),
),
SizedBox(
height: 50.0,
),
//########ATTACHEMENT & PHOTOS
Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
//Attachement
FlatButton(
onPressed: () {
},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.attach_file),
Text('Attachement'),
],
)
),
onTap: () {
_openGallery(context);
},
),
),
//Photo
FlatButton(
onPressed: () {(); },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {
},
),
),
//Voice Recording
FlatButton(
onPressed: () { },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ConstrainedBox(
constraints: BoxConstraints(
minWidth: iconSize,
minHeight: iconSize,
maxWidth: iconSize,
maxHeight: iconSize,
),
child: Image.asset('assets/icons/microphone.png', fit: BoxFit.cover),
),
Text('Recording'),
],
)
),
onTap: () {
MyApp_AZERTY();
},
),
),
],
),
)
),
]
),
),
Container(
child:
_showImageView(context)
),
SizedBox(
height: 150.0,
),
//CANCEL & SAVE
Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 1.0, color: Colors.grey),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
child:
FlatButton(
child: Text("Cancel",style: TextStyle(
fontSize: 18.0,fontWeight: FontWeight.bold,color: Colors.grey
)
),
onPressed: (){
final loForm = _captureFormKey.currentState;
loForm.reset();
},
),
),
Container(
child: FlatButton(
child: Text("Save",style: TextStyle(
fontSize: 18.0,fontWeight: FontWeight.bold,color: Colors.blue
)),
// Border.all(width: 1.0, color: Colors.black),
onPressed: (){}
loForm.reset();
showSimpleFlushbar(context, 'Task Saved',_valueTaskNameSaved, Icons.mode_comment);
}
loForm.reset();
},
),
),
]
),
),
],
),
) :
The problem is getImage does not return a type of file, but a type of
Future<PickedFile>
So you need to do the following.
final image = await ImagePicker().getImage(source: ImageSource.gallery);
this.setState(() {
imageFile = File(image.path);
});

Add the same Widget on click -Flutter

I'm facing difficulties to make it. When I click the button, I would like it to appear at the bottom with a delete option. The option with multi_select_chip does not work well with SDK version 2.12, Can anyone tell me how to do it?
Is adding buttons a good idea, and what would it look like to create a new widget that will be combined with data from the button that I just clicked?
I am new to flutter, and any help will be really useful.
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
List<Widget> widgets = <Widget>[];
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: widgets,
),
);
}
Widget show() {
return Center(
child: Column(
children: widgets,
),
);
}
#override
void initState() {
widgets = <Widget>[
// Text(
// "This is a sample text",
// style: TextStyle(fontSize: 40),
// ),
Container(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Wrap(
spacing: 8.0,
// line interval
runSpacing: 8.0,
children: <Widget>[
ConstrainedBox(
constraints:
const BoxConstraints.tightFor(width: 70, height: 35),
child: ElevatedButton(
child: Text(
'Lion',
style: TextStyle(fontSize: 13),
),
onPressed: () {
debugPrint("clicked");
debugPrint('widgets: $widgets');
widgets.insert(1, SampleContainer());
setState(() {});
},
style: ElevatedButton.styleFrom(
primary: purple, elevation: 10)),
),
const SizedBox(width: 8.0),
ConstrainedBox(
constraints:
const BoxConstraints.tightFor(width: 125, height: 35),
child: ElevatedButton(
child: Text(
'Flamingo',
style: TextStyle(fontSize: 13),
),
onPressed: () {
debugPrint("clicked");
debugPrint('widgets: $widgets');
widgets.insert(1, SampleContainer());
setState(() {});
},
style: ElevatedButton.styleFrom(
primary: purple, elevation: 10)),
),
const SizedBox(width: 8.0),
ConstrainedBox(
constraints:
const BoxConstraints.tightFor(width: 105, height: 35),
child: ElevatedButton(
child: Text(
'Hippo',
style: TextStyle(fontSize: 13),
),
onPressed: () {
debugPrint("clicked");
debugPrint('widgets: $widgets');
widgets.insert(1, SampleContainer());
setState(() {});
},
style: ElevatedButton.styleFrom(
primary: purple, elevation: 10)),
),
// ]),
// const SizedBox(width: 80.0),
// Row(children: <Widget>[
// const SizedBox(width: 40.0),
ConstrainedBox(
constraints:
const BoxConstraints.tightFor(width: 100, height: 35),
child: ElevatedButton(
child:
Text("Horse", style: TextStyle(fontSize: 13)),
onPressed: () {
debugPrint("clicked");
debugPrint('widgets: $widgets');
widgets.insert(1, SampleContainer());
setState(() {});
},
style: ElevatedButton.styleFrom(
primary: purple, elevation: 10)),
),
const SizedBox(width: 8.0),
ConstrainedBox(
constraints:
const BoxConstraints.tightFor(width: 135, height: 35),
child: ElevatedButton(
child: Text("Tiger",
style: TextStyle(fontSize: 13)),
onPressed: () {
debugPrint("clicked");
debugPrint('widgets: $widgets');
widgets.insert(1, SampleContainer());
setState(() {});
},
style: ElevatedButton.styleFrom(
primary: purple, elevation: 10)),
),
const SizedBox(width: 4.0),
ConstrainedBox(
constraints:
const BoxConstraints.tightFor(width: 70, height: 35),
child: ElevatedButton(
child: Text("INNE", style: TextStyle(fontSize: 13)),
onPressed: () {
debugPrint("clicked");
debugPrint('widgets: $widgets');
widgets.insert(1, SampleContainer());
setState(() {});
},
style: ElevatedButton.styleFrom(
primary: purple, elevation: 10)),
),
]),
]),
),
];
}
// Widget show() {
// return SampleContainer();
// }
}
class SampleContainer extends StatefulWidget {
#override
_SampleContainerState createState() => _SampleContainerState();
}.
class _SampleContainerState extends State<SampleContainer> {
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Wrap(
spacing: 8.0,
// line interval
runSpacing: 8.0,
children: <Widget>[
const SizedBox(width: 40.0),
ElevatedButton(
child: Text("INNE"),
onPressed: () {
setState(() {});
},
)
]),
] ),);
}
}
Here is the example.
import 'package:flutter/material.dart';
class WidgetPicker extends StatefulWidget {
const WidgetPicker({Key key}) : super(key: key);
#override
_WidgetPickerState createState() => _WidgetPickerState();
}
class _WidgetPickerState extends State<WidgetPicker> {
List<String> values = [
'Hello',
'Hello2',
'Hello3',
];
List<String> pickedValues = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildValues(),
const SizedBox(
height: 30,
),
_buildPickeds(),
],
),
);
}
Widget _buildValues() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: values
.map(
(value) => GestureDetector(
onTap: () {
if (pickedValues.contains(value)) {
pickedValues.remove(value);
} else {
pickedValues.add(value);
}
setState(() {});
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
color: Colors.blueGrey,
child: Text(
value,
),
),
),
)
.toList(),
);
}
Widget _buildPickeds() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: pickedValues
.map(
(value) => GestureDetector(
onTap: () {
if (pickedValues.contains(value)) {
pickedValues.remove(value);
} else {
pickedValues.add(value);
}
setState(() {});
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
color: Colors.red,
child: Text(
value,
),
),
),
)
.toList(),
);
}
}

Flutter: is there any possibility to send the button value to the text field?

I am Writing a small quiz game, in which I am pressing the button and these buttons are going to the empty text fields, I don't know how to send the text of the button to the text fields.
here is my code :
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: NinjaCard()));
class NinjaCard extends StatefulWidget {
#override
_NinjaCardState createState() => _NinjaCardState();
}
class _NinjaCardState extends State<NinjaCard> {
String result = "";
String shaka = "";
var text;
String str;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: Text('Animals'), backgroundColor: Colors.green),
body: Padding(
padding: EdgeInsets.all(15),
child: Column(
children: <Widget>[
Center(
child: Image.asset('lib/photo-1495594059084-33752639b9c3.jpg'),
),
SizedBox(width: 10, height: 10),
Row(children: <Widget>[
Container(
color: Colors.grey,
width: 40.0,
child: Text('$result', style: TextStyle(fontSize: 10.0, height: 2.0, color: Colors.black)),
),
SizedBox(width: 10),
Container(
color: Colors.grey,
width: 40.0,
child: Text('$shaka', style: TextStyle(fontSize: 10.0, height: 2.0, color: Colors.black)),
),
SizedBox(width: 15),
Row(
children: <Widget>[
SizedBox(
width: 50,
child: RaisedButton(
onPressed: () {},
color: Colors.green,
splashColor: Colors.red,
child: Text('S', style: TextStyle(backgroundColor: Colors.green, fontSize: 20, color: Colors.white)),
),
),
SizedBox(width: 15),
SizedBox(
width: 50,
child: RaisedButton(
onPressed: () {},
color: Colors.green,
splashColor: Colors.red,
child: Text('T', style: TextStyle(backgroundColor: Colors.green, fontSize: 20, color: Colors.white)),
),
),
SizedBox(width: 15),
],
),
]),
],
),
),
);
}
}
In a simple case, I would go with a stateful widget and array of letters. Of course, it could be created and sized dynamically, below I only explain the basic idea with some simplifications (no duplicate checks, no shuffling):
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'App',
home: GuessTheWordWidget(),
);
}
}
class GuessTheWordWidget extends StatefulWidget {
#override
_GuessTheWordWidgetState createState() => _GuessTheWordWidgetState();
}
class _GuessTheWordWidgetState extends State<GuessTheWordWidget> {
String _word = 'Goldfish';
List<String> _input = List.generate(8, (_) => '');
int _position = 0;
void _press(int rune) {
setState(() {
if (_position < _input.length) {
print('Position ${_position}, rune: ${String.fromCharCode(rune)}');
_input[_position++] = String.fromCharCode(rune);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('App'),
),
body: Center(
child: Column(children: <Widget>[
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: _input
.map((letter) => Container(
margin: const EdgeInsets.all(15.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent)),
child: Text(letter),
))
.toList())),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: _word.runes
.map((rune) => RaisedButton(
onPressed: () => _press(rune),
child: Text(String.fromCharCode(rune),
style: TextStyle(fontSize: 20)),
))
.toList())),
])),
);
}
}
Go play with this code at DartPad: https://dartpad.dev/69bae58772305c74f1688193076ecaef!

CustomScrollView object does not update with input from StatefulBuilder

I have a CustomScrollView that gets updated upon user input. The actual items in the ListView are in a SliverChildBuilderDelegate inside the CustomScrollView which is inside the body of the Scaffold object (see the code below). If a user adds an item in the form that is inside the StatefulBuilder which is inside a showDialog object, the item does not get added to the planets list which thus does not update the ListView. I think the problem is caused by the StatefulBuilder which I need to update my DropdownButton.
My code:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() {
runApp(MaterialApp(
home: HomePage(),
));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class Planet {
final String id;
final String name;
final String location;
final String distance;
final String gravity;
final String image;
const Planet({this.id, this.name, this.location, this.distance, this.gravity, this.image});
}
class Coin {
int id;
String name;
Coin(this.id, this.name);
static List<Coin> getCoins() {
return <Coin>[
Coin(1, 'coin1'),
Coin(2, 'coin2'),
Coin(3, 'coin3'),
Coin(4, 'coin4'),
Coin(5, 'coin5'),
];
}
}
class MenuItem {
String title;
String icon;
Color color;
Function func;
MenuItem(this.title, this.icon, this.color, this.func);
}
class _HomePageState extends State<HomePage> {
List<Coin> _coins = Coin.getCoins();
List<DropdownMenuItem<Coin>> _dropdownMenuItems;
Coin _selectedCoin;
#override
void initState() {
_dropdownMenuItems = buildDropdownMenuItems(_coins);
_selectedCoin = _dropdownMenuItems[0].value;
super.initState();
_menuItems = createMenuItems();
_selectedMenuItem = _menuItems.first;
}
MenuItem _selectedMenuItem;
List<MenuItem> _menuItems;
List<Widget> _menuOptionWidgets = [];
List<MenuItem> createMenuItems() {
final menuItems = [
new MenuItem("Dashboard", 'assets/images/dashboard.png', Colors.black, () => new Dashboard()),
new MenuItem("Cows", 'assets/images/cow.png', Colors.green, () => new Cows()),
];
return menuItems;
}
_onSelectItem(MenuItem menuItem) {
setState(() {
_selectedMenuItem = menuItem;
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
Navigator.of(context).pop(); // close side menu
}
List<DropdownMenuItem<Coin>> buildDropdownMenuItems(List coins) {
List<DropdownMenuItem<Coin>> items = List();
for (Coin coin in coins) {
items.add(
DropdownMenuItem(
value: coin,
child:
Text(
coin.name,
style: TextStyle(
fontSize: 18.0,
color: Colors.black87,
fontWeight: FontWeight.bold
),
),
),
);
}
return items;
}
onChangeDropdownItem(Coin selectedCoin, StateSetter setState) {
setState(() {
_selectedCoin = selectedCoin;
print('${_selectedCoin.name}');
});
}
final coinController = TextEditingController();
final amountController = TextEditingController();
final purposeController = TextEditingController();
#override
void dispose() {
// Clean up the controller when the widget is disposed.
coinController.dispose();
amountController.dispose();
purposeController.dispose();
super.dispose();
}
List<Planet> planets = [];
#override
Widget build(BuildContext context) {
_menuOptionWidgets = [];
DateTime now = DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd kk:mm').format(now);
for (var menuItem in _menuItems) {
_menuOptionWidgets.add(new Container(
decoration: new BoxDecoration(
color: menuItem == _selectedMenuItem
? Colors.grey[200]
: Colors.white),
child: new ListTile(
leading: new Image.asset(menuItem.icon),
onTap: () => _onSelectItem(menuItem),
title: Text(
menuItem.title,
style: new TextStyle(
fontSize: 20.0,
color: menuItem.color,
fontWeight: menuItem == _selectedMenuItem
? FontWeight.bold
: FontWeight.w300),
))));
_menuOptionWidgets.add(
new SizedBox(
child: new Center(
child: new Container(
margin: new EdgeInsetsDirectional.only(start: 20.0, end: 20.0),
height: 0.3,
color: Colors.grey,
),
),
),
);
}
double screenHeight;
screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
title: Text('Dashboard'),
backgroundColor: Color.fromRGBO(53, 73, 94, 0.9),
elevation: 0.0,
// leading: Container(),
),
drawer: new Drawer(
child: new ListView(
children: <Widget>[
new Container(
child: new ListTile(
leading: new CircleAvatar(
backgroundColor: Colors.black,
radius: 40.0,
child: Text(
"L",style: TextStyle(
color: Colors.orange,
fontSize: 46.0),
),
),
title: Text("Welcome",style: TextStyle(fontSize: 46.0),)
),
margin: new EdgeInsetsDirectional.only(top: 20.0),
color: Colors.white,
constraints: BoxConstraints(maxHeight: 90.0, minHeight: 90.0)),
new SizedBox(
child: new Center(
child: new Container(
margin:
new EdgeInsetsDirectional.only(start: 10.0, end: 10.0),
height: 0.3,
color: Colors.black,
),
),
),
new Container(
color: Colors.white,
child: new Column(children: _menuOptionWidgets),
),
],
),
),
floatingActionButton: new Container(
width: 120.0,
height: 120.0,
padding: const EdgeInsets.only(bottom:40.0),
child: FloatingActionButton(
child: Icon(Icons.add,size: 50.0),
elevation: 0.0,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Container(
margin: EdgeInsets.only(
top: screenHeight / 5,
bottom: screenHeight / 4
),
padding: EdgeInsets.only(left: 10, right: 10),
child: Card(
color: Color.fromRGBO(53, 73, 94, 0.9),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 8,
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: Text(
"Create",
style: Style.headerTextStyle
),
),
Divider(
color: Colors.white
),
SizedBox(
height: 15,
),
DropdownButton(
value: _selectedCoin,
items: _dropdownMenuItems,
onChanged: (selectedCoin) {
setState(() {
_selectedCoin = selectedCoin;
print('${_selectedCoin.name}');
});
}, //onChangeDropdownItem(_selectedCoin, setState),
),
SizedBox(
height: 15,
),
TextFormField(
decoration: InputDecoration(
labelText: "Amount",
hasFloatingPlaceholder: true,
labelStyle: Style.commonTextStyle
),
controller: amountController,
),
SizedBox(
height: 20,
),
TextFormField(
decoration: InputDecoration(
labelText: "What is it for?",
hasFloatingPlaceholder: true,
labelStyle: Style.commonTextStyle
),
controller: purposeController,
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment
.spaceEvenly,
children: <Widget>[
Expanded(
child: Container(),
),
ButtonTheme(
minWidth: 150.0,
child: RaisedButton(
padding: EdgeInsets.all(8.0),
child: Text('Share',
style: TextStyle(
fontSize: 24,
color: Colors.black87,
fontWeight: FontWeight.bold
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
18.0)
),
color: Colors.white,
splashColor: Colors.blueGrey,
onPressed: () {
setState(() {
planets.add(Planet(
id: '1',
// TODO need to adjust this
name: purposeController.text,
location: '€' + amountController.text,
distance: formattedDate,
gravity: 'test',
image: _setImage(), // TODO might have to pass _selectedCoin as parameter
)
);
});
Navigator.pop(context);
},
),
),
],
),
],
),
),
),
);
}
);
},
);
},
),
),
body: Column(
children: <Widget>[
new Expanded(
child: new Container(
color: Color.fromRGBO(53, 73, 94, 0.9),
child: new CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
new SliverPadding(
padding: const EdgeInsets.symmetric(vertical: 0.0),
sliver: new SliverFixedExtentList(
itemExtent: 152.0,
delegate: new SliverChildBuilderDelegate(
(context, index) => new PlanetRow(planets[index]),
childCount: planets.length,
),
),
),
],
),
),
),
],
),
);
}
}
The expected result is that the object from user input gets added to the planets list. The Sliver object then gets the updated planets list which shows the user input in a Planet Card. Any help will be greatly appreciated!