Flutter save page content after routing - flutter

i have a favorite icon that exist on page (A) that changes it's color whenever i click, the problem is when i move to another page and go back to page (A) icon goes to regular color, it doesn't save the changes on page , is there a way to keep the changes even after moving from page to page ?
Thanks.

If you push and pop back, then you can find the saved state from the route. How-ever if you pop back, current page state will be removed from stack. To handle this, you need to use state-management property. You can use StateProvider in this case, or the thing that suit for your project.
Demo:
class PageA extends StatefulWidget {
PageA({Key? key}) : super(key: key);
#override
_PageAState createState() => _PageAState();
}
class _PageAState extends State<PageA> {
Color color = Colors.deepOrange;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("PAge A"),
),
body: Center(
child: Column(
children: [
Container(
width: 400,
height: 400,
color: color,
alignment: Alignment.center,
child: Text("init Color:deepOrange "),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => PageB(),
));
},
child: Text("Move to B"),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
color = Colors.deepPurple;
});
},
),
);
}
}
class PageB extends StatefulWidget {
const PageB({Key? key}) : super(key: key);
#override
_PageBState createState() => _PageBState();
}
class _PageBState extends State<PageB> {
Color color = Colors.greenAccent;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("PAge B"),
),
body: Center(
child: Column(
children: [
Container(
width: 400,
height: 400,
color: color,
alignment: Alignment.center,
child: Text("init Color:greenAccent "),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PageC(),
),
);
},
child: Text("Move to C"),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Move Back to A, you can find last saved state"),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
color = Colors.black;
});
},
),
);
}
}
class PageC extends StatefulWidget {
PageC({Key? key}) : super(key: key);
#override
_PageCState createState() => _PageCState();
}
class _PageCState extends State<PageC> {
Color color = Colors.amberAccent;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("PAge C"),
),
body: Center(
child: Column(
children: [
Container(
width: 400,
height: 400,
color: color,
child: Center(child: Text("init Color:amberAccent ")),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PageB(),
),
);
},
child: Text("Push to B, will assing new state on route"),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
"pop to B\n if you pop then current state of Page B will be visible"),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
color = Colors.pink;
});
},
),
);
}
}

Related

widget into List<Widget> does not update into build method even if i call setState

i have the following simple full code
import 'dart:developer';
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
List myListWidget = [];
late bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
setState(() {
myListWidget.add(
Container(
width: 50,
height: 50,
color: isColorWhie?Colors.white:Colors.red,
)
);
});
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...myListWidget,
TextButton(
onPressed: (){
setState(() {
isColorWhie = !isColorWhie; // here never update
log('done');
});
},
child: const Text('tab to Change color',style: TextStyle(color: Colors.white),)
)
],
),
),
),
);
}
}
i tap on any point on screen to add Container into myListWidget thn call setState(() {}); to update ui.
everything fine now but when i change the isColorWhie to true it should change the color to white but it never update !
i am totally confused why it does not update ? And how could i handle with this ?
For base color change, I am using a separate button, also switching the list value.
One thing variable does update the UI, you need to handle state inside the item(state-management property) or reinitialize the variable to get update state.
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
List<bool> myListWidgetState = [];
bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(
() {
myListWidgetState.add(isColorWhie);
},
);
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...myListWidgetState.map(
(e) {
return Container(
width: 50,
height: 50,
color: e ? Colors.white : Colors.red,
);
},
),
TextButton(
onPressed: () {
myListWidgetState = myListWidgetState.map((e) => !e).toList();
setState(() {});
print(isColorWhie);
},
child: const Text(
'tab to Change color',
style: TextStyle(color: Colors.white),
),
),
TextButton(
onPressed: () {
setState(() {
isColorWhie = !isColorWhie;
});
print(isColorWhie);
},
child: const Text(
'tab to Change base color',
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
);
}
}
Since you create a container as an object in GestureDetector and save it to your list, it will not change. It is now permanently saved (of course as long as you do not delete the element) as an entry in your list.
Your logic works exactly as you programmed it. For example, if you were to recompile the app and press the TextButton and then anywhere on your screen, a white container would also appear.
If you want to dynamically change the color of all containers at once, then you can do the following:
class _TestState extends State<Test> {
int containerCounter = 0;
late bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
containerCounter++;
});
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 50,
child: ListView.builder(
shrinkWrap: true,
itemCount: containerCounter,
itemBuilder: ((context, index) {
return Container(
height: 50,
color: isColorWhie ? Colors.white : Colors.red,
);
}),
),
),
TextButton(
onPressed: () {
setState(() {
isColorWhie = !isColorWhie; // here never update
});
},
child: const Text(
'tab to Change color',
style: TextStyle(color: Colors.white),
))
],
),
),
),
);
}
}

How to Change the label of an existing chip in flutter?

I'm using chips in my code when I tap on chip a counter is displayed, I want to update the chip label with when count is added.
Widget returnWidget() {
return InkWell(
child: Chip(
label: Text(temp!),
),
onTap: () {
print(temp);
_showMyDialog();
},
);
}
This is the widget I'm using to add multiple chips.
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
scrollable: false,
title: const Text('Add Count'),
content: Container(
height: 50,
width: 50,
alignment: Alignment.center,
padding: const EdgeInsets.all(3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
AddCount(),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
{
setState(() {
_itemCount = 0;
});
}
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Add'),
onPressed: () {
if(count==0) {
setState((){
temp = temp! + _itemCount.toString();
Text(temp!);
count++;
});
}
print(text);
},
),
],
);
},
);
}
This is the code block which is showing a counter dialog. I want to update chip label on add.
Hello here I have a solution, I did not see more details about your code but here I did a working solution, the variable you want to update should be located inside the classed where is used but you can also use state management or InheritedWidget to update variables globally:
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Example(),
);
}
}
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
#override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
int temp = 0; // declare the variable inside the class you want to update it
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
scrollable: false,
title: const Text('Add Count'),
content: Container(
height: 50,
width: 50,
alignment: Alignment.center,
padding: const EdgeInsets.all(3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
// AddCount(),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Add'),
onPressed: () {
setState((){
temp = temp += 1; // update the chip UI
});
Navigator.of(context).pop();
},
),
],
);
},
);
}
Widget returnWidget() {
return InkWell(
child: Chip(
label: Text("count $temp"), // <-- new change
),
onTap: () {
print(temp);
_showMyDialog();
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red,
body: Center(
child: Container(
margin: const EdgeInsets.all(32),
child: returnWidget(),
),
),
);
}
}

Flutter how to make bottomsheet which stay always on top of every page

bottomsheet(not bottombar) which stay alway on top of entire app.if open an page it always stay on top
WidgetsApp(
debugShowCheckedModeBanner: false,
color: Colors.pink,
builder: (context, child) => Stack(
children: [
GetMaterialApp(
debugShowCheckedModeBanner: false,
color: Colors.pink,
home: Scaffold(
backgroundColor: Colors.amber,
body: Center(
child: TextButton(
onPressed: () {},
child: Text(
'data',
),
),
),
),
),
//bottomsheet
Positioned(
bottom: 0,
left: 0,
right: 0,
child: PlayerSheet(),
)
],
),
);
something like above
Create something like this as your page wrapper:
class StickyPageWrapper extends StatelessWidget {
final Widget child;
const StickyPageWrapper({Key key, this.child}) : super(key: key);
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Stack(
fit: StackFit.expand,
children: [
child,
Positioned(
left: 0,
bottom: 0,
child: Hero(
tag: 'bottom_sheet',
child: Container(
color: Colors.orange,
height: size.height / 4,
width: size.width,
),
),
)
],
);
}
}
Then use it like this for one page:
class Page1 extends StatelessWidget {
const Page1({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StickyPageWrapper(
child: Container(
color: Colors.white38,
child: Center(
child: ElevatedButton(
child: Text('Go to page 2'),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Page2()));
},
)),
)),
);
}
}
Then for the other page:
class Page2 extends StatelessWidget {
const Page2({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StickyPageWrapper(
child: Container(
color: Colors.white38,
child: Center(
child: ElevatedButton(
child: Text('Go back to page 1'),
onPressed: () {
Navigator.of(context).pop();
},
)),
)),
);
}
}
And so on, so you wrap your every page.
I added a Hero animation to your BottomSheet when navigating between pages: https://flutter.dev/docs/development/ui/animations/hero-animations so that it looks bit nicer and more natural.
Hope this helps, let me know if I can help further.
Note: This is actually not a BottomSheet widget if that was your idea, because typically that one is created implicitly by ScaffoldState.showBottomSheet, for persistent bottom sheets, or by showModalBottomSheet, for modal bottom sheets.

Flutter - Is it possible to show a snackbar inside another Container than the one used to trigger .show?

Is it possible to have the snackbar appearing only in another widget?
I am trying something like that so that when we click on the button the snackbar would only be embedded inside the Container, not appearing outside of it but it is not working:
#override
Widget build(BuildContext context) {
BuildContext snackContext;
return Stack(
children: [
Builder(builder: (BuildContext context) {
snackContext = context;
return Container(height: 300, width: 300, child: Text('Test'));
}),
TextButton(
onPressed: () {
ScaffoldMessenger.of(snackContext).showSnackBar(
SnackBar(
backgroundColor: Color(0x44000000),
content: Text(
'Test of snackbar',
),
),
);
},
)
],
);
}
Please advise~
Save the correct context in the State. This code works for me:
class _TestPageState extends State<TestPage> with TickerProviderStateMixin {
BuildContext snackContext;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 300,
width: 200,
child: Scaffold(
backgroundColor: Colors.deepPurple,
body: Builder(builder: (BuildContext context) {
snackContext = context;
return Container(height: 300, width: 300, child: Text('Test'));
}),
),
),
Center(
child: TextButton(
onPressed: () {
Scaffold.of(snackContext).showSnackBar(
SnackBar(
backgroundColor: Color(0x44000000),
content: Text(
'Test of snackbar',
),
),
);
},
child: Text('data'),
),
)
],
),
);
}
}
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}

issue in image showing on full body

following is my code I have taken the screenshot of the image and showing here but the image is showing side border
class ResultImage extends StatelessWidget {
final Image image;
// File file;
ResultImage({Key key, this.image}) : super(key: key);
#override
Widget build(BuildContext context) {
// file=File(image);
return Scaffold(
appBar: AppBar(
title: Text("View Image"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
tooltip: 'Share',
onPressed: () => {},
),
],
),
body: Container(
child: image,
));
}
}
Resolved issue by applying height: double.infinity,width: double.infinity to fix your issue.
class ResultImage extends StatelessWidget {
final Image image;
// File file;
ResultImage({Key key, this.image}) : super(key: key);
#override
Widget build(BuildContext context) {
// file=File(image);
return Scaffold(
appBar: AppBar(
title: Text("View Image"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
tooltip: 'Share',
onPressed: () => {},
),
],
),
body: Container(
height: double.infinity,
width: double.infinity,
child: image,
));
}
}
Try with this;
class ResultImage extends StatelessWidget {
final Image image;
// File file;
ResultImage({Key key, this.image}) : super(key: key);
#override
Widget build(BuildContext context) {
// file=File(image);
return Scaffold(
appBar: AppBar(
title: Text("View Image"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
tooltip: 'Share',
onPressed: () => {},
),
],
),
body: Expanded(
child: image,
));
),
),
);
}
}
Should set image fit as 'fit: BoxFit.fill', ex -
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Stack'),
),
body:
GestureDetector(
child: Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: AssetImage('images/splash.png'),
fit: BoxFit.fill),
),
),
onTap: () {},
),
);
}