How to watch when the Slidable changes state on Flutter - flutter

I'm utilize o Slidable on app Flutter and put as ListTile child.
So far ok.
I'm problem is i would like when I slide it to the left the text keeps appearing on the screen, as shown in the image below.(Red == Title)
At the moment the text is hidden when I swipe, as per the image.(Red == Title)
I saw that when I swipe this attribute changes state Slidable.of(context)?.animation.isCompleted
And I also verified that in my Row title of ListTile, if I line up the title as End, the title will appear msm by swiping.
So I thought, as this Slidable.of(context)?.animation.isCompleted attribute changes state I align my Row to Start or End.
But I couldn't find a way to monitor this attribute, so that when it changes I can rebuild my Row. I tried to put it as Stream but I wasn't successful. Because it looks like it doesn't generate an event, it just changes the value.
I don't know how I could do it, if anyone has any tips...
Code:
#override
Widget build(BuildContext) {
return Slidable(
key: const ValueKey(1),
endActionPane: ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (ctx) => {
Get.to(() => const CredentialOperationScreen(),
arguments:
RouteDetailCredential(itemCredential: itemCredential))
},
backgroundColor: ConstsColors.orangeAccent,
foregroundColor: Colors.white,
icon: Icons.info_outline,
),
SlidableAction(
onPressed: (ctx) => {
Get.to(() => const CredentialOperationScreen(),
arguments:
RouteDeleteCredential(itemCredential: itemCredential))
},
backgroundColor: const Color.fromRGBO(219, 32, 32, 1),
foregroundColor: Colors.white,
icon: Icons.delete_outline,
),
],
),
child: Builder(
builder: (ctx) {
return Container(
child: _listTile(ctx),
decoration: const BoxDecoration(
border: Border(
bottom:
BorderSide(color: ConstsColors.greyColorOpacity))));
},
));
}
Widget _listTile(context) {
return ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
itemCredential.icon,
color: Colors.black,
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
itemCredential.name,
style: const TextStyle(
fontFamily: 'Roboto',
fontSize: 16,
),
),
),
],
),
onTap: () => {
Slidable.of(context)?.animation.isCompleted == true
? Slidable.of(context)?.close()
: Slidable.of(context)?.openEndActionPane()
},
trailing: const Icon(Icons.check_circle_outline, color: Colors.green),
);
}

Related

Custom widget of app bar with a humburger menu as ElevatedButton with a Drawer doesn't work OnPressed

I am facing a problem with my custom app bar. I would like it to have a drawer but it doesn't work. I just don't know how to make it being able to open.
It is a custom app bar widget named Pasek (which stands for top bar in my language).
It has a logo picture which on click moves you to the first page of the app.
Next to it there is humburger menu with a drawer but I do not know why it doesn't work. I click on it and nothing happens.
Any ideas?
class Pasek extends StatelessWidget with PreferredSizeWidget {
#override
Size get preferredSize => Size.fromHeight(50.0);
const Pasek({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AppBar(
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 35.0),
child: ElevatedButton(
child: Icon(Icons.menu, color: Colors.white),
onPressed: () {
Scaffold(
endDrawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: const <Widget>[
DrawerHeader(
decoration: BoxDecoration(
color: Colors.black,
),
child: Text(
'Menu',
style: TextStyle(
color: Colors.pink,
fontSize: 24,
),
),
),
ListTile(
leading: Icon(Icons.message),
title: Text('Messages'),
),
ListTile(
leading: Icon(Icons.account_circle),
title: Text('Profile'),
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
),
],
),
),
);
},
)),
],
backgroundColor: Colors.black,
title: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FirstPage(),
),
);
}, // Image tapped
child: Image.asset(
'images/logo.png',
fit: BoxFit.scaleDown,
height: 30,
width: 200,
),
));
}
}

How to collapse the popup menu in Flutter

How can I narrow the width of the popup menu in the navbar?
How can I zoom the icon and text?
I can't open the width tag, I think a different customization is required.
actions: <Widget>[
PopupMenuButton<_MenuValues>(
color: const Color(0xFF212121),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15.0))
),
itemBuilder: (BuildContext context) => [
PopupMenuItem(
child: ListTile(
leading: Icon(Icons.settings, color: Colors.white),
title: Text("Settings", style: TextStyle(color: Colors.white)),
),
value: _MenuValues.settings
),
],
onSelected: (value) {
switch(value) {
case _MenuValues.settings:
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => settings(),
));
break;
}
},
),
],
use sizedBox
PopupMenuItem(
value: 1,
// row has two child icon and text.
child: SizedBox(
width: 500,
child: Row(
children: [
Icon(Icons.settings , size: 10,),
Text("Settings", style: TextStyle(fontSize: 10),)
],
),
)
),
],

Using provider between different screens and appBar in flutter

I'm using Provider in my flutter app. I was able to change one widget with another one, without using set state. That was great!
My feature consist that when I tap in the button 'Añadir al carrito', a number over the shopping car change, increasing one by one.
This is the part of my code that I put in the button, that is inside the body of my scaffold using the provider.of:
final _numCompras = Provider.of<MyShoppingCart>(context);
return Padding(
padding: const EdgeInsets.only(top: 15.0),
child: GestureDetector(
onTap: () {
_numCompras.numCompras = _numCompras.numCompras + 1;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text('Producto Añadido'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: '',
onPressed: () {
},
),
));
},
child: Container(
height: 80,
width: double.infinity,
decoration: BoxDecoration(
color: Constants.kColorRojo,
borderRadius: BorderRadius.circular(60),
border: Border.all(width: 1, color: Colors.black),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Añadir al Carrito',
style: TextStyle(
color: Colors.white,
fontFamily: 'Poppins',
fontSize: 20,
),
),
SizedBox(
width: 15,
),
Icon(
Icons.shopping_cart_outlined,
color: Colors.white,
size: 30,
),
],
),
),
),
),
);
}
This is my class using ChangeNotifier
int _numCompras = 0;
get numCompras => _numCompras;
set numCompras(int newValue) {
_numCompras = newValue;
notifyListeners();
}
}
And in my main.dart I`m putting the ChangeNotifierProvider, because I thing that one contain all of the rest widgets.
class JuniorsApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<MyShoppingCart>(
create: (context) => MyShoppingCart(),
//builder: ,
)
],
child: MaterialApp(
theme: ThemeData.light().copyWith(
primaryColor: Color(0xFFd51921),
scaffoldBackgroundColor: Color(0xFFf2f2f2),
),
home: PageStart(),
initialRoute: PageStart().ID_PageStart,
routes: {
page_IniciarSesion().ID_PageIniciarSesion: (context) =>
page_IniciarSesion(),
PageStart().ID_PageStart: (context) => PageStart(),
RegistroNombrePage().ID_PageRegistroNombre: (context) =>
RegistroNombrePage()
},
debugShowCheckedModeBanner: false,
),
);
}
}
And finally the code of my appBar that is the widget that I`m changing:
Widget build(BuildContext context) {
bool _hasBackButton = hasBackArrow ?? true;
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
return Selector<MyShoppingCart,int>(
selector: (_, model) => model.numCompras,
builder: (context, numCompras, _) {
return SafeArea(
child: Material(
elevation: 15,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (_hasBackButton)
RoundedIconButton(
iconData: Icons.arrow_back_ios,
press: () {
Navigator.pop(context, MaterialPageRoute(
builder: (context) {
return Selector(builder: (context, numCompras, _){}, selector: (_, model) => model.numCompras);
},
)
);
}
),
Text(
this.title == null ? 'Junior \'s Tacos' : this.title,
style: Constants.kFuenteAppBar,
),
this.hasCart
? _widgetShoppingCar(context, height, width, numCompras)
: Spacer() ,
],
),
),
),
);
},
);
}
Widget _widgetShoppingCar(context, height, width, _numCompras) {
return Stack(
children: [
RoundedIconButton(
iconData: Icons.shopping_cart_outlined,
press: () {
_viewShop = !_viewShop;
this.changeAppBarShop(_viewShop);
/*Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CartPage(),
),
);*/
},
),
Positioned(
bottom: height * 0.04,
left: width * 0.09,
child: Container(
width: width * 0.05,
height: height * 0.025,
decoration: BoxDecoration(
color: Colors.red[500],
border: Border.all(
color: Colors.red[500],
),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Center(
child: Text(
'${_numCompras}',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
)),
),
)
],
);
}
The thing is that it works fine, but when I do Navigator.pop from the appBar. The count over the shopping car come back to zero.
Here is how its working at the moment
Could anyone give a me a tip about this?
thanks!
Well, if anyone have this kind of problem. The issue for me was that I have two ChangeNotifierProvider. One in my main.dart and the other one in my widget that contain the button. I remove the last one and now its working.

How to create a custom Dialog in flutter

I want to create a custom dialog as shown below. I am able to create a normal dialog with two buttons(the positive and negative buttons). But I searched a lot about creating custom dialog like the one shown below but in vain.
showAlertDialog(BuildContext context) {
// set up the buttons
Widget cancelButton = FlatButton(
child: Text("Cancel"),
onPressed: () {},
);
Widget continueButton = FlatButton(
child: Text("Continue"),
onPressed: () {},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("Action"),
content: Text("Would you like to continue learning how to use Flutter alerts?"),
actions: [
cancelButton,
continueButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Now I want to have these buttons and the image as the children of the dialog and the icon button 'X' in the bottom to close the dialog. Any help is appreciated. I am a complete beginner in flutter.
For it, we create a custom dialog
1. Custom Dialog Content class
class CustomDialog extends StatelessWidget {
dialogContent(BuildContext context) {
return Container(
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 10.0,
offset: const Offset(0.0, 10.0),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min, // To make the card compact
children: <Widget>[
Image.asset('assets/images/image.jpg', height: 100),
Text(
"Text 1",
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 16.0),
Text(
"Text 1",
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 24.0),
Align(
alignment: Alignment.bottomCenter,
child: Icon(Icons.cancel),
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0.0,
backgroundColor: Colors.transparent,
child: dialogContent(context),
);
}
}
2. Call Custom Dialog on Click:
RaisedButton(
color: Colors.redAccent,
textColor: Colors.white,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return CustomDialog();
});
;
},
child: Text("PressMe"),
),

Problem with List builder repeat the data when adding or removing item in the list

I'm new to flutter. When I adding new item or removing an item from the list, the list builder does update the list, but the problem is that the list builder also displaying the previous item list and showing new updated item list. So what I want to do is keeping the new updated item list instead of old item list.
class AlarmPage extends StatefulWidget {
final String title;
AlarmPage({Key key, this.title}) : super(key: key);
#override
_AlarmPageState createState() => _AlarmPageState();
}
class _AlarmPageState extends State<AlarmPage> {
String alarmName;
// Test Function
void _addAlarm() {
setState(() {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddAlarm()));
});
}
#override
void initState() {
super.initState();
Provider.of<AlarmsProvider>(context, listen: false).getLocalStorage();
}
#override
Widget build(BuildContext context) {
List<Widget> allWidgetsAlarms = List<Widget>();
return Consumer<AlarmsProvider>(builder: (context, alarmProviderItem, _) {
List<String> localAlarms = alarmProviderItem.alarms;
if (localAlarms != null) {
localAlarms.forEach((item) {
allWidgetsAlarms.add(
Stack(
children: <Widget>[
InkWell(
child: Container(
color: Color(0xff212121),
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
// Alarm Name & Title
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 2),
)),
child: Row(
children: <Widget>[
Icon(Icons.alarm, color: Colors.yellow),
SizedBox(width: 20.0),
Text('$item',
style: TextStyle(
color: Color(0xffC1C1C1),
fontSize: 15.0,
fontWeight: FontWeight.w900)),
SizedBox(height: 5),
],
),
),
SizedBox(height: 10),
// Alarm Time & Toggle Switch
Container(
child: Row(
children: <Widget>[
Text(
'Time',
style: TextStyle(
fontSize: 30, color: Colors.white),
),
SizedBox(width: 20),
Text(
'AM / PM',
style: TextStyle(
fontSize: 20, color: Color(0xffB5B5B5)),
),
SizedBox(width: 150),
Icon(Icons.switch_camera, color: Colors.yellow),
],
),
),
// Alarm Repeat
Container(
child: Row(children: <Widget>[
Text(
'Repeat',
style: TextStyle(
fontSize: 11, color: Color(0xff616161)),
),
Container(
child: DaySelector(
value: null,
onChange: (value) {},
color: Colors.yellow[400],
mode: DaySelector.modeFull,
),
),
]),
),
],
),
),
onLongPress: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddAlarm(item: item)));
},
),
SizedBox(height: 180),
],
),
);
print(item);
});
}
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text('Azy Alarm'),
centerTitle: true,
),
body: Container(
decoration: BoxDecoration(
image: const DecorationImage(
fit: BoxFit.cover,
image: AssetImage('assets/images/background_image(dark).png')),
),
// child: ListView(children: allWidgetsAlarms),
child: ListView.builder(
itemCount: allWidgetsAlarms.length,
padding: const EdgeInsets.all(8.0),
itemBuilder: (BuildContext context, int index) {
return allWidgetsAlarms[index];
}),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Colors.blue,
elevation: 0,
onPressed: _addAlarm,
),
);
});
}
}
So I think your issue is this line: allWidgetsAlarms.add( You construct allWidgetsAlarms in your builder, but the builder is not called again every time you Consumer rebuilds, hence it is just appending the new contents to the end of the list. To fix this, keep your original initialization of allWidgetsAlarms just at the top of the builder in your Consumer, add the following line:
allWidgetsAlarms = List<Widget>();
This will resert allWidgetsAlarms. Hope it helps!