Flutter: SnackBar inside Dismissible widget is not working properly - flutter

My Home Screen is a Scaffold with a list of Dismissible widgets at its body. The child of each Dismissible is a custom widget I created, named Box. I have a FloatingActionButton that takes me to a new screen where I can add more Boxes to the list. (Each Box receive a String as an argument, that is used as its title).
I want the method onDismissed to show a SnackBar with the text "(Title of the box) excluded". However, this is not working as expected. The problem is that it always displays the title of the last box included, and not the title of the one I just dismissed. For example, if I add a Box named "Box 1", and then a Box named "Box 2", and then I dismiss the "Box 1", the snackbar will say "Box 2 excluded".
What am I doing wrong?
Here is the relevant code:
import 'package:flutter/material.dart';
import 'box.dart';
import 'addCounter.dart';
class Home extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
List<String> lista;
void incrementLista(String novoItem) {
print('$lista');
setState(() {
lista.add(novoItem);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counters'),
backgroundColor: Colors.black,
),
body: ListView.builder(
itemCount: lista.length,
itemBuilder: (context, index) {
return Dismissible(
background: Container(color: Colors.grey[800], child: Icon(Icons.delete, color: Colors.grey[100])),
key: Key(lista[index]),
onDismissed: (direction) {
setState(() {
lista.removeAt(index);
});
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(lista[index] + ' excluded.')));
},
child: Box(lista[index]));
},
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.grey[1000],
onPressed: () {
//Navega para tela de adicionar tarefa
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddCounter(f: incrementLista)));
},
child: Icon(Icons.add, color: Colors.white)),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomNavigationBar(
//backgroundColor: Colors.grey[50],
unselectedItemColor: Colors.grey[700],
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text('List'),
),
BottomNavigationBarItem(
icon: Icon(Icons.insert_chart),
title: Text('Chart'),
),
],
// currentIndex: _selectedIndex,
selectedItemColor: Colors.blue,
//onTap: _onItemTapped,
),
);
}
}
And here is the code of the addCounter.dart:
import 'package:flutter/material.dart';
class AddCounter extends StatefulWidget {
final Function f;
AddCounter({#required this.f});
#override
_AddCounterState createState() => _AddCounterState();
}
class _AddCounterState extends State<AddCounter> {
final myController = TextEditingController();
#override
void dispose() {
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add a counter'),
backgroundColor: Colors.blue,
),
body: Column(children: [
Padding(
padding: EdgeInsets.all(15),
child: TextField(
controller: myController,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2)),
hintText: 'Type a name for the counter'),
),
),
RaisedButton(
color: Colors.green,
onPressed: () {
widget.f(myController.text);
Navigator.pop(context);
},
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
)
]));
}
}

I think the problem is that you first remove the item of the list. When you show the SnackBar the item is already removed so you can't access it in the list. So I would suggest to first show the Snackbar and then remove the item.
Like this: (In your itemBuilder)
return Dismissible(
background: Container(color: Colors.grey[800], child: Icon(Icons.delete,
color: Colors.grey[100])),
key: Key(lista[index]),
onDismissed: (direction) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(lista[index] + ' excluded.')));
setState(() {
lista.removeAt(index);
});
},
child: Box(lista[index]));
},

Related

SetState not updating listview

Im trying to make it so when you press search it creates a listtile. It works but for it to work I have to click the button and then rebuild the app for it to appear. I was looking at some other posts but I could not find anything that worked. The main parts to look at is I have a function that adds a listtile. I have a button with an on press to create the tile. And I have the children of container at the bottom as the list of created listtiles.
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Widget> _listOfWidgets = [];
#override
Widget build(BuildContext context) {
_addItemToList() {
List<Widget> tempList =
_listOfWidgets; // defining a new temporary list which will be equal to our other list
tempList.add(ListTile(
key: UniqueKey(),
leading: Icon(Icons.list),
trailing: FlatButton(
onPressed: () async {},
//Download Link
child: Text(
"Download",
style: TextStyle(color: Colors.green, fontSize: 15),
),
),
title: Text("")));
this.setState(() {
_listOfWidgets =
tempList; // this will trigger a rebuild of the ENTIRE widget, therefore adding our new item to the list!
});
}
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: currentTheme.currentTheme(),
home: Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
setState(() {
currentTheme.switchTheme();
});
},
icon: Icon(Icons.wb_sunny),
),
IconButton(
onPressed: () async {
await FirebaseAuth.instance.signOut();
},
icon: Icon(Icons.exit_to_app),
),
],
backgroundColor: Colors.blue,
title: Text("Home"),
),
body: ListView(
children: [
ListTile(
leading: SizedBox(
width: 300,
child: TextField(
controller: search,
decoration: InputDecoration(
labelText: "Enter Manga Name",
),
),
),
trailing: ElevatedButton(
onPressed: () async {
_addItemToList();
},
child: Text("Search")),
),
Container(
margin: EdgeInsets.all(15),
width: 100,
height: 515,
color: Colors.black12,
child: ListView(
children: _listOfWidgets,
))
],
)));
}
}
try add below code
if you update status you need setState()
A better way to state management is to use a BLoC or Provider package.
...
onPressed: () {
setState(() {
_addItemToList();
});
},
...
Figured it out after a bit of tinkering. Fix for me was to add key: UniqueKey(), to my ListView. I had keys added to my ListTiles instead of the actual ListView.
onPressed: () {
setState(() {
_addItemToList();
});
},
The Problem Solution is :
List<Widget> tempList = <Widget>[];
_addItemToList() {
tempList.addAll(
_listOfWidgets); // defining a new temporary list which will be equal to our other list
tempList.add(ListTile(
key: UniqueKey(),
leading: Icon(Icons.list),
trailing: FlatButton(
onPressed: () async {},
//Download Link
child: Text(
"Download",
style: TextStyle(color: Colors.green, fontSize: 15),
),
),
title: Text("")));
this.setState(() {
_listOfWidgets =
tempList; // this will trigger a rebuild of the ENTIRE widget, therefore adding our new item to the list!
});
}

Getting Error while Home widget (MyHomepage) loading

I am getting The following error while Run my app default page (Homepage) .
════════ Exception caught by widgets library ═══════════
The following ArgumentError was thrown building MyHomePage(dirty, dependencies: [MediaQuery, _EffectiveTickerMode], state: _MyHomePageState#7da5f(ticker inactive)):
Invalid argument(s)
**The Tracker showing the following reasons:**
The relevant error-causing widget was:
MyHomePage file:///F:/Orangebd/app/GoogleDriveClone-Flutter/lib/Screen/Home.dart:37:15
When the exception was thrown, this was the stack:
#0 _StringBase.+ (dart:core-patch/string_patch.dart:272:57)
#1 _MyHomePageState.build (package:googledriveclone_flutter/Screen/Home.dart:133:45)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4716:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4599:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4772:11)
...
══════════════════════════════════════════
During that error, the screen appears something like that
Here is my Home page code
import 'package:fab_circular_menu/fab_circular_menu.dart';
//import 'package:file_picker/file_picker.dart';
import 'package:floating_action_bubble/floating_action_bubble.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:googledriveclone_flutter/Screen/Files.dart';
import 'package:googledriveclone_flutter/Screen/HomeScreen.dart';
import 'package:googledriveclone_flutter/Screen/LoginPage.dart';
import 'package:googledriveclone_flutter/Screen/Profile.dart';
import 'package:googledriveclone_flutter/Widget/constants.dart';
import 'package:prompt_dialog/prompt_dialog.dart';
import 'package:sk_alert_dialog/sk_alert_dialog.dart';
import 'package:storage_capacity/storage_capacity.dart';
import 'IssudFile.dart';
void main() {
runApp(HomePage());
}
class HomePage extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
try {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Digilocker',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Digilocker'),
);
}
catch(e){
print('Loading expception of page'+e.toString());
}
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
Widget _widgetBody = HomeScreen();
int _currrentIndex = 0;
Animation<double> _animation;
AnimationController _animationController;
TextEditingController _foldername = TextEditingController();
String _fileName;
var scaffoldKey = GlobalKey<ScaffoldState>();
bool isFolder;
double _diskSpace = 0;
var _freespace ;
var _freespacemb;
var _occupiedSpace ;
var _totalSpace;
#override
void initState() {
// TODO: implement initState
// _controller.addListener(() => _extension = _controller.text);
_getStorgeInfo();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 300),
);
final curvedAnimation = CurvedAnimation(curve: Curves.easeInOut, parent: _animationController);
_animation = Tween<double>(begin: 0, end: 1).animate(curvedAnimation);
// initDiskSpace();
super.initState();
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _onItemTapped(int index) async{
setState(() {
if(index == 0){
_currrentIndex = index;
_widgetBody = HomeScreen();
}
else if(index == 1){
_currrentIndex = index;
_widgetBody = MyIssuedDocScreen();
}
else if(index == 2){
_currrentIndex = index;
_widgetBody = Center(child: Text('Shared documents'),);
}
else if(index == 3){
_currrentIndex = index;
_widgetBody = MyDriveScreen();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
endDrawerEnableOpenDragGesture: false, // This way it will not open
// endDrawer: Drawer(),
drawer: new Drawer(
elevation: 10,
child: new ListView(
padding: EdgeInsets.all(0),
children: <Widget>[
DrawerHeader(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset('assets/digi_locker.png', width: MediaQuery.of(context).size.width*0.30,),
SizedBox(height: 10,),
Text('Available space: '+_freespace+'\t (MB)'),
]
),
decoration: BoxDecoration(
color: kPrimaryLightColor,
),
),
ListTile(
leading: Icon(Icons.person),
title: Text('My profile'),
onTap: () {
// Get.back();
Get.to(profilePage());
},
),
Divider(),
ListTile(
leading: Icon(Icons.create_new_folder),
title: Text('Create folder'),
onTap: () {
// Get.back();
_showMyDialog();
},
),
ListTile(
leading: Icon(Icons.cloud_upload_rounded),
title: Text('File upload'),
onTap: () {
// Get.back();
},
),
ListTile(
leading: Icon(Icons.six_ft_apart_outlined),
title: Text('Issued documents'),
onTap: () {
// Get.back();
},
),
Divider(),
ListTile(
leading: Icon(Icons.translate_rounded),
title: Text('Change lagnuage'),
onTap: () {
// Get.back();
//Get.offAll(LoginPage());
//Do some stuff here
//Closing programmatically - very less practical use
scaffoldKey.currentState.openEndDrawer();
},
),
ListTile(
leading: Icon(Icons.logout),
title: Text('Logout'),
onTap: () {
// Get.back();
Get.offAll(LoginPage());
//Do some stuff here
//Closing programmatically - very less practical use
scaffoldKey.currentState.openEndDrawer();
},
)
],
),
),
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
brightness: Theme.of(context).brightness,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children:
[
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(35)),
color: Colors.grey.shade50,
),
child: TextFormField(
decoration: InputDecoration(
hintText: "Search in locker",
border: InputBorder.none,
icon: Container(
margin: EdgeInsets.only(left: 10),
child: Icon(Icons.search, color: kPrimaryColor,)
),
),
),
),
),
]
),
iconTheme: IconThemeData(color: kPrimaryColor),
actions: <Widget>[
IconButton(
onPressed: (){
print("Sync started");
showSnackMessage(context,"Sync Started please wait...", scaffoldKey,'');
},
icon: Icon(
Icons.sync,
color:kPrimaryColor,
),
),
IconButton(
icon: Container(
height: 50,
width: 50,
margin: EdgeInsets.all(5),
child: CircleAvatar(
radius: 14.0,
backgroundColor: Colors.white,
child: CircleAvatar(
radius: 14.0,
backgroundColor: Colors.grey[200],
backgroundImage: NetworkImage("https://qph.fs.quoracdn.net/main-qimg-11ef692748351829b4629683eff21100.webp"),
),
),
),
onPressed: () {
// do something
},
)
],
),
body: SafeArea(
child: Container(
padding: EdgeInsets.all(15.0),
child: _widgetBody
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
//Init Floating Action Bubble
floatingActionButton: FloatingActionBubble(
// Menu items
items: <Bubble>[
// Floating action menu item
Bubble(
title:"Upload",
iconColor :kPrimaryColor,
bubbleColor : Colors.white.withOpacity(0.9),
titleStyle:TextStyle(fontSize: 16 , color: kPrimaryColor),
icon:Icons.cloud_upload,
onPress: () {
// OpenFilePicker();
_animationController.reverse();
_openFileType(context);
},
),
// Floating action menu item
Bubble(
title:"Folder",
icon:Icons.create_new_folder,
iconColor :kPrimaryColor,
bubbleColor : Colors.white.withOpacity(0.9),
titleStyle:TextStyle(fontSize: 16 , color: kPrimaryColor),
onPress: () {
_animationController.reverse();
print('creating folder');
_showMyDialog();
},
),
//Floating action menu item
],
// animation controller
animation: _animation,
// On pressed change animation state
onPress: _animationController.isCompleted
? _animationController.reverse
: _animationController.forward,
// Floating Action button Icon color
iconColor: kPrimaryColor,
// Flaoting Action button Icon
icon: AnimatedIcons.menu_close,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currrentIndex,
type: BottomNavigationBarType.fixed,
showSelectedLabels: true,
showUnselectedLabels: true,
selectedItemColor: kPrimaryColor,
onTap: _onItemTapped,
items: [
BottomNavigationBarItem(
icon: _currrentIndex==0?Icon(Icons.home,size: 25,):Icon(Icons.home_outlined,size: 25),
title: Text("Home")
),
BottomNavigationBarItem(
icon: _currrentIndex==1?Icon(Icons.file_download_done,size: 25,):Icon(Icons.file_download_done_outlined,size: 25),
title: Text("Issued")
),
BottomNavigationBarItem(
icon: _currrentIndex==2?Icon(Icons.supervised_user_circle,size: 25,):Icon(Icons.supervised_user_circle,size: 25),
title: Text("Shared")
),
BottomNavigationBarItem(
icon: _currrentIndex==3?Icon(Icons.folder,size: 25,):Icon(Icons.folder_open,size: 25),
title: Text("My locker")
),
],
), );
}
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Colors.white,
elevation: 13,
title: Text('Create folder'),
content: TextField(
onChanged: (value) { },
controller: _foldername,
decoration: InputDecoration(hintText: "your folder/directory name",
suffixIcon: IconButton(
onPressed: () => _foldername.clear(),
icon: Icon(Icons.clear),
),
),
),
actions: <Widget>[
TextButton(
child: Text('Cancel', style: TextStyle(color: Colors.red),),
onPressed: () {
//Navigator.pop(_);
Navigator.of(context).pop();
// _animationController.reverse();
},
),
TextButton(
child: Text('Create', style: TextStyle(color: kPrimaryColor),),
onPressed: () {
createFolder(context, scaffoldKey, _foldername.text.toString()) ;
Get.back();
//Navigator.of(context).pop();
// _animationController.reverse();
},
),
],
);
},
);
}
void _openFileType(BuildContext context) {
SKAlertDialog.show(
context: context,
type: SKAlertType.radiobutton,
radioButtonAry: {'Certificate': 1, 'Signature': 2, 'NID': 3, 'Passport': 4, 'Driving licence': 5},
title: 'Choose File category',
onCancelBtnTap: (value) {
print('Cancel Button Tapped');
Navigator.of(context).pop(false);
},
onRadioButtonSelection: (value) {
print('onRadioButtonSelection $value');
},
);
}
/* Future<void> initDiskSpace() async {
double diskSpace = 0;
diskSpace = await DiskSpace.getFreeDiskSpace;
if (!mounted) return;
setState(() {
_diskSpace = diskSpace;
});
}
*/
Future<void> _getStorgeInfo() async{
_freespace = await StorageCapacity.getFreeSpace;
//_freespacemb = await StorageCapacity.toMegaBytes(double.parse(_freespace.toString()));
_occupiedSpace = await StorageCapacity.getOccupiedSpace;
_totalSpace = await StorageCapacity.getTotalSpace;
}
}
NOTE: if I Hot Reload this page, it's working okay again
Please help.
the problem is, you are getting your data in the initState method, but your widget's build is being completed before initializing the data to _freespace, and that's why the error is appearing.
as a solution, I suggest removing _getStorgeInfo() call from initState, and implementing the following structure:
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
endDrawerEnableOpenDragGesture: false, // This way it will not open
// endDrawer: Drawer(),
drawer: new Drawer(
...
),
appBar: AppBar(
...
),
body: SafeArea(
child: Container(
padding: EdgeInsets.all(15.0),
child: FutureBuilder(
future: _getStorgeInfo(),
builder: (context, snapshot) {
if(snapshot.connectionState!=ConnectionState.Done) return CircularProgressIndicator();
return _widgetBody;
},
),
),
));
}

currentIndex to have onPressed function

I am making a flutter app and i am working on the bottom navigation bar and i want to know if i can make the buttons to redirect the user to a new page UI from the app.I used this 'package:bubble_bottom_bar/bubble_bottom_bar.dart' and i don't know how to cal currentIndex = 1 ,2,3,4 to redirect to a new page when the user pressed the icon. I tried to add to my BubbleBottomBarItem a onPressed action but it doesn't work.
This is the code that i am using
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:tariffo/favoriteProviders.dart';
import 'package:tariffo/messages_list.dart';
import 'package:bubble_bottom_bar/bubble_bottom_bar.dart';
import 'HomePage.dart';
class BarDetail extends StatefulWidget {
#override
_BarDetailState createState() => _BarDetailState();
}
class _BarDetailState extends State<BarDetail> {
int currentIndex;
#override
void initState() {
super.initState();
currentIndex = 0;
}
changePage(int index) {
setState(() {
currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.8),
child: BubbleBottomBar(
opacity: 0.2,
backgroundColor: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(16.0)),
currentIndex: currentIndex,
hasInk: true,
inkColor: Colors.black12,
hasNotch: true,
fabLocation: BubbleBottomBarFabLocation.end,
onTap: changePage,
items: <BubbleBottomBarItem>[
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(Icons.dashboard, color: Colors.black),
activeIcon: Icon(Icons.dashboard, color: Colors.red),
title: Text("Home")),
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(Icons.favorite_border, color: Colors.black),
activeIcon: Icon(Icons.dashboard, color: Colors.red),
title: Text("Saved")),
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(Icons.search, color: Colors.black),
activeIcon: Icon(Icons.dashboard, color: Colors.red),
title: Text("Search")),
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(Icons.send, color: Colors.black),
activeIcon: Icon(Icons.dashboard, color: Colors.red),
title: Text("Messages")),
],
),
);
}
}
and this are the pages that i want the buttons to open : FavoriteProviders(),MessageList()
Another way to go about it is by using PageView, create a PageController and assign it to the property of PageView called controller.
The controller - PageController _controller = PageController();
The PageView itself
PageView(
controller: _controller;
children: <Widget>[
FavoriteProviders(),
MessageList()
]
)
So FavoriteProviders() is now index 0, and MessageList() is now index 1
You can use one of these in the onTap to navigate to that page
_controller.jumpToPage(index) or
controller.animateToPage(index, duration: Duration(milliseconds: 500), curve: Curves.easeIn)
Pass in whatever you want for the duration and curve.
You should have something like this:
A list of pages:
final List<Widget> _pages = [
FavoriteProviders(),
MessageList()
];
A Scaffold where the body: _pages[currentIndex],
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: _bubbleBottomNavBar(),
body: _pages[currentIndex],
)
}
where _bubbleBottomNavBar() is your bottom bar.
OR
Replace on onTap function with:
BubbleBottomBar(
opacity: 0.2,
backgroundColor: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(16.0)),
currentIndex: currentIndex,
hasInk: true,
inkColor: Colors.black12,
hasNotch: true,
fabLocation: BubbleBottomBarFabLocation.end,
onTap: (index) {
if(index == 1)
Navigator.push(
context,
MaterialPageRoute(builder: (context) => FavoriteProviders()),
);
if (index == 2)
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MessageList()),
);
},
items: <BubbleBottomBarItem>[
[...]
]
)

Method setState() is not updating the UI (Flutter)

My home screen is a Scaffold with a ListView at its body and a floating action button at the bottom. The action button takes the user to a second screen, where he can type a text into a text input and press save. The save button calls a method at the home screen that adds the text to the List variable over which ListView is based. The problem is: the List variable is being updated (I can see on the log), but the setState is not updating the ListView. What am I doing wrong?
Here's the code from the Home Screen:
import 'package:flutter/material.dart';
import 'addCounter.dart';
class Home extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
List lista = <Widget>[];
void incrementLista(newItem) {
print('$lista');
setState(() {
lista.add(Box('newItem'));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List of Counters'),
backgroundColor: Colors.deepPurple[1000],
),
body: Builder(
builder: (context)=>
Center(
child: ListView(children: lista),
),),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.grey[1000],
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddCounter(f: incrementLista)));
},
child: Icon(Icons.add, color: Colors.white)),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomNavigationBar(
unselectedItemColor: Colors.grey[700],
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text('Lista'),
),
BottomNavigationBarItem(
icon: Icon(Icons.insert_chart),
title: Text('Gráfico'),
),
],
selectedItemColor: Colors.blue,
),
);
}
}
And here is the code from the addCounter.dart:
import 'package:flutter/material.dart';
class AddCounter extends StatefulWidget {
final Function f;
AddCounter({#required this.f});
#override
_AddCounterState createState() => _AddCounterState();
}
class _AddCounterState extends State<AddCounter> {
final myController = TextEditingController();
#override
void dispose() {
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add a counter'),
backgroundColor: Colors.blue,
),
body: Column(children: [
Padding(
padding: EdgeInsets.all(15),
child: TextField(
controller: myController,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2)),
hintText: 'Type a name for the counter'),
),
),
RaisedButton(
color: Colors.green,
onPressed: () {
widget.f(myController.text);
Navigator.pop(context);
},
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
)
]));
}
}
I don't think the code for the Box widget is relevant. It is basically a card with a title.
#pskink gave me an answer that worked perfectly. Here it is:
basically you should not use such a list of widgets, data and presentation layers should be separated, instead you should use a list of data only, see https://flutter.dev/docs/cookbook/gestures/dismissible for more info

How to change navigation drawer hamburger menu icon to arrow icon when open/close drawer layout - Flutter?

When I created drawer layout following the Add a Drawer to a screen docs, it works OK. However, I have a problem, this is menu Icon.
In Android, I setup drawer layout with DrawerToggle and when I open drawer, menu icon is going to change to arrow icon and when I close drawer, arrow icon is going to change to menu icon.
In Flutter, it do not work as above.
If you understand my problem, please help me. I have search a lot, but not found solution. So I want to ask everyone. Thankyou so much.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final appTitle = 'Drawer Demo';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: Center(child: Text('My Page!')),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the Drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Item 1'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
);
}
}
Use StateFulWidget so you can access setState method to change icon
In your state class
Define a Global Key
final GlobalKey<ScaffoldState> _key = GlobalKey();
Define a boolean to check whether Drawer is open.
bool _isDrawerOpen = false;
Add these to your state class
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Title'),
leading: IconButton(
icon: _isDrawerOpen ? Icon(Icons.menu) : Icon(Icons.arrow_back),
onPressed: onPressed,
),
),
drawer: WillPopScope(child: Drawer(), onWillPop: onPop),
body: //body
key: this._key,
);
}
void onPressed() {
if (!_isDrawerOpen) {
this._key.currentState.openDrawer();
} else {
Navigator.pop(context);
}
setState(() {
_isDrawerOpen = !_isDrawerOpen;
});
}
void onPop() {
if (_isDrawerOpen) {
setState(() {
_isDrawerOpen = false;
});
}
Navigator.pop(context);
}
To change hamburger icon while drawer open and also to display drawer below app bar:
I have declared "METHOD 1" and "METHOD 2" in my code which are in comments.
"METHOD 1" allows to open drawer and change icon with drawer controller callback.
"METHOD 2" allows to open drawer when we click hamburger icon The problem is if we used can't click on hamburger icon when use drawer controller.
import 'package:flutter/material.dart';
class MyNavDrawerController extends StatefulWidget {
createState() {
return StateKeeper();
}
}
class StateKeeper extends State<MyNavDrawerController> {
// Declare a new variable which will increment on FAB tap
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final appBarColor = const Color(0xFFd2527f);
var myIcon = new Icon(Icons.list);
DrawerCallback drawerCallback(bool status) {
Fluttertoast.showToast(
msg: "Drawer " + status.toString(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: appBarColor,
textColor: Colors.white,
fontSize: 14.0);
setState(() {
setMenuIcon(status);
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
primary: true,
appBar: AppBar(
title: Text("Parent Scaffold"),
leading: new IconButton(icon: myIcon,
onPressed:(){
_scaffoldKey.currentState.openDrawer();
}
)
),
// METHOD 1
/*body: DrawerController(
child: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Andy Rubin'),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
title: Text('Home'),
onTap: () {
setState(() {
Navigator.pop(context);
});
},
),
ListTile(
title: Text('About us'),
onTap: () {
Navigator.pop(context);
Fluttertoast.showToast(
msg: "About us clicked! :)",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
},
),
ListTile(
title: Text('Notifications'),
onTap: () {
Navigator.pop(context);
Fluttertoast.showToast(
msg: "Notifications clicked! :)",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: Colors.blue,
textColor: Colors.white,
fontSize: 18.0);
},
)
],
),
),
alignment: DrawerAlignment.start, drawerCallback: drawerCallback
),*/
// METHOD 2
/*body: Scaffold(
key: _scaffoldKey,
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Andy Rubin'),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
title: Text('Home'),
onTap: () {
Fluttertoast.showToast(
msg: "Home clicked! :)",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: appBarColor,
textColor: Colors.white,
fontSize: 14.0);
setState(() {
Navigator.pop(context);
});
},
),
ListTile(
title: Text('About us'),
onTap: () {
Navigator.pop(context);
Fluttertoast.showToast(
msg: "About us clicked! :)",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
},
),
ListTile(
title: Text('Notifications'),
onTap: () {
Navigator.pop(context);
Fluttertoast.showToast(
msg: "Notifications clicked! :)",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: Colors.blue,
textColor: Colors.white,
fontSize: 18.0);
},
)
],
),
),
)*/
);
}
void setMenuIcon(bool isDrawerOpen){
if(isDrawerOpen){
myIcon = new Icon(Icons.list);
}else{
myIcon = new Icon(Icons.arrow_back);
}
}
}
Below I attach a snippet of my code that I think is the easiest way to have a custom hamburger icon. The main part of the code is to use leading:!
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
leading: Builder(
builder: (context) => IconButton(
icon: Icon(
Icons.sort,
color: Colors.black54,
),
onPressed: () => Scaffold.of(context).openDrawer(),
tooltip:
MaterialLocalizations.of(context).openAppDrawerTooltip,
)),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('App'),
),
ListTile(
title: Text('Item 1'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
Navigator.pop(context);
},
),
],
),
),)