I want to send data to a new screen without navigating to it on pressing a button in flutter - flutter

I want to send data to different screen on pressing a button.
I am using
Get.to(Screen(), arguments: [data])
I only want to send data
It send the data but also navigate to it
Please give me. Some. Hint

Let's suppose we have two Stateful widget class.
The CheetahInput has a static variable data that will get data from any class And
we have a check on TEXT() when variable data is empty simply show "old value" in TEXT() widget
if variable data is not empty then show its value on Text() widget.
class CheetahInput extends StatefulWidget {
Static String? data;
#override
_CheetahInputState createState() => _CheetahInputState();
}
class _CheetahInputState extends State<CheetahInput> {
#override
Widget build(BuildContext context) {
return Center(child: Text(SignIn.data!=null?SignIn.data!:'old value'),); }
}
The TestEditor Class has saveButton and navigatebutton, while the savebutton will assign data into static variable "data" in SignIn class,
And the NavigateButton will Navigate to that screen where you have sended the data
class TestEditor extends StatefulWidget {
#override
_TestEditorState createState() => _TestEditorState();
}
class _TestEditorState extends State<TestEditor> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
floatingActionButton:Container( width:MediaQuery.of(context).size.width,
child: Row(
children: [Spacer(),
FloatingActionButton(onPressed: (){Navigator.push(context, MaterialPageRoute(builder:(context)=>SignIn(context)));},child: Text('NavigateButton'),),
Spacer(),
FloatingActionButton(onPressed: (){SignIn.data='I am data from new page';},child: Text('saveButton'),),Spacer(),
],
),
);
}
}
So in this way, you send data to other screens without navigate to that screen at meantime

Related

Is it possible to share and update one screen's reactive value in another screen without Provider?

So I have this block of code in a widget that navigates to another screen:
screen_one.dart
class ScreenOne extends StatefulWidget {
const ScreenOne({ super.key });
#override
State<ScreenOne> createState() => _ScreenOneState();
}
class _ScreenOneState extends State<ScreenOne> {
List<String> state = [''];
#override
Widget build(BuildContext context) {
return Column(
MaterialButton(
onPressed: () => Navigator.pushNamed(context, '/screen-two'),
child: Text('Click here.')
),
Text(state[0]),
);
}
}
screen_two.dart
class ScreenTwo extends StatelessWidget {
const ScreenTwo({ super.key });
#override
Widget build(BuildContext context) {
return Container();
}
}
Basically I need to pass the state variable from ScreenOne to ScreenTwo and then update it there (in ScreenTwo)
ScreenTwo needs to display the same thing as ScreenOne and add() a new item to the state list when some button is clicked which should show on both the screens.
Its just one simple List so I am trying to avoid using provider.
Is it possible to do though?
I'm currently just passing it through the Navigator:
screen_one.dart
Navigator.pushNamed(
context,
'/post-info',
arguments: state,
),
screen_two.dart
Widget build(BuildContext context) {
final List<String> post = ModalRoute.of(context)!.settings.arguments as List<String>;
// ...
}
first I want to recommend you when things go bigger and more complex, it's better to use a state management approach, However since you did say that you have only one List you can simply use a ValueNotifier, with ValueListenableBuilder:
// this should be outside widget classes, maybe in a custom-made class or just in a global scope.
ValueNotifier stateNotifier = ValueNotifier([""]);
now in the places you want to use that state, you can use ValueListenableWidget like this:
ValueListenableBuilder(
valueListenable: stateNotifier,
builder: (context, value, child) {
return Column(
children: [
Text('${state[0]}'),
MaterialButton(
onPressed: () {
Navigator.pushNamed(context, '/screen-two'),
},
child: Text('click'),
),
],
);
},
);
}
}
and any other place where you want to see that state get updates, you need to use ValueListenableWidget.
Now, for executing a method like add() on the List and notify the widgets, you need to assign a new value for it like this:
void addInTheList(String elem) {
List current = stateNotifier.value;
current.add(elem);
// this exactly what will be responsible for updating.
stateNotifier.value = current;
}
now, you can just call addInTheList and expect it to update in all of them:
addInTheList("Example");

Flutter-getx, widget does not re-render when RxMap set to a new value

I'm building a widget that renders based on the contents of an RxMap. I start with the RxMap initialized to empty, and upon clicking a button set the RxMap to contain a new value. After setting the new value for the RxMap, the widget does not re-render to display the new map values.
Here's my code:
(EDIT: included all the boilerplate as well to prevent confusion. Each class is in a separate file with relevant imports in all the other files.)
class MyController extends GetxController {
var selectedItem = {}.obs;
}
class MyBinding extends Bindings {
#override
void dependencies() {
Get.put(MyController());
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext highContext) {
return GetMaterialApp(
title: 'App',
getPages: [
GetPage(
name: "/test",
page: () => MyClass(),
binding: MyBinding()),
],
initialRoute: "/test",
);
}
}
final saController = Get.find<MyController>();
class MyClass extends StatelessWidget {
Widget build(context) {
print(saController.selectedItem);
return Scaffold(
child: Column(
children: [
Obx(() => Container(
child: Text(saController.selectedItem.toString())
)),
TextButton(
child: Text("click"),
onPressed: (() {
saController.selectedItem = RxMap({"test": "item"});
saController.selectedItem.refresh();
saController.update();
print(saController.selectedItem);
})
)
]
)
);
}
}
The first print statement correctly prints the empty object to the console and the onPressed print statement correctly prints the new object with its key and value included to the console, but the widget does not re-render with the new value. refresh() and update() don't appear to do anything.
This seems to be specific to RxMap, I've been able to get other datatypes to update on change successfully, e.g. swapping out the RxMap value for a boolean value and toggling it from true to false on click causes the widget to re-render correctly without changing any other parts of the code.
Your UI will not trigger an update unless the value of a Rx variable (selectedItem.value) is changed. But you are updating the Rx variable (selectedItem) itself.
Therefore,you need to change saController.selectedItem = RxMap({"test": "item"}); to saController.selectedItem.value = {"test": "item"};
And I think you don't actually need to call refresh() and update() anymore.

flutter slider not updating widget variables

am playing around with the slider widget on flutter, and I can't figure out why it does not update certain values in a different widget, example code is shown below;
When i move the slider, it has no issues moving, but the value i'm trying to update on the other widget does not update even though the onchanged is updating the variable passed through in a set state accordingly.
any help would be greatly appreciated!
Scaffold Code
class TestPage extends StatelessWidget {
static const id = "test_page";
#override
Widget build(BuildContext context) {
double testValue = 0;
return Scaffold(
body: Column(
children: [
Text("Hello World"),
TestBoxNumber(
numberDisplay: testValue,
),
TestSlider(testValue: testValue),
],
),
);
}
}
Slider Code
class TestSlider extends StatefulWidget {
double testValue;
TestSlider({required this.testValue});
#override
_TestSliderState createState() => _TestSliderState();
}
class _TestSliderState extends State<TestSlider> {
#override
Widget build(BuildContext context) {
return Slider(
activeColor: themeData.primaryColorLight,
value: widget.testValue,
min: 0,
max: 100,
divisions: 100,
label: widget.testValue.round().toString(),
onChanged: (double value) {
setState(() {
widget.testValue = value;
});
},
);
}
}
Different Widget Code
class TestBoxNumber extends StatefulWidget {
final double numberDisplay;
const TestBoxNumber({required this.numberDisplay});
#override
_TestBoxNumberState createState() => _TestBoxNumberState();
}
class _TestBoxNumberState extends State<TestBoxNumber> {
#override
Widget build(BuildContext context) {
return Container(
child: Text(widget.numberDisplay.toString()),
);
}
}
The problem is that you are constructing TestBoxNumber widget in such a way that value (testValue) will always be the same (testValue is never returned out of the TestSlider widget).
How to overcome this issue?
You can make your TestPage a StatefullWidget. Then create callback from TestSlider, so when you change value in TestSlider you will call some function in TestPage (with setState in it, causing re-rendering your page).
Or if you don't want your whole TestPage widget to be Statefull (if, let's say, you predict a lot of other static widgets in it and you don't want them to be re-rendered because you just moved a slider), you can create wrapper Statefull widget and put both TestSlider and TestBoxNumber widgets in it. This is more flexible approach, imho.
Here is small scheme of what I mean by wrapping two widgets in another one:
UPD: btw, there is no point in making TestBoxText a statefull widget if it's only purpose is to display a text and you pass it's value through the constructor.

Issue regarding nested MaterialApp.router() in Flutter Navigator 2.0

Ask the question denotes I'm trying to create a nested Navigator using Navigator 2.0 for my Flutter web app. Below is the starting point of my app.
void main() {
runApp(App());
}
class App extends StatefulWidget {
#override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
#override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: AppRouteParser(), routerDelegate: AppRouterDelegate(),
title: "Demo",
);
}
}
As you can see I've added a MaterialApp.router() to handle all the top layer navigations.
Now I wanted to add a nested navigator inside this one which will work the same way as above and will handle the url changes properly. That why I decided to use the same MaterialApp.router() widget inside as a child as my nested Navigator.
Everything is working fine after doin this but I am getting two debug banners like the image below :
This makes me wonder if I using the proper method to achieve the result.
The child Navigator belongs in Page1 widget of the root navigator like below is the Navigator widget of root MaterialApp.router:
class AppRouterDelegate extends RouterDelegate<AppRoute>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoute> {
final GlobalKey<NavigatorState> _navigatorKey;
bool isPage1A = false;
bool isPage1B = false;
bool isUnknown = false;
AppRouterDelegate() : _navigatorKey = GlobalKey<NavigatorState>();
#override
Widget build(BuildContext context) {
return Navigator(
pages: [
MaterialPage(key: ValueKey("Page 1"),child: Page1(_valueChangeCallback)),
if(isPage1A)
MaterialPage(key: ValueKey("Page 1A"),child: Page1A(_valueChangeCallback)),
if(isPage1B)
MaterialPage(key: ValueKey("Page 1B"),child: Page1B(_valueChangeCallback)),
/* if(isUnknown)
MaterialPage(key: ValueKey("404"),child: TestPage()) */
],
onPopPage: (route,result){print("Pop !!!!"); return route.didPop(result);}
);
}
_valueChangeCallback(bool value,String subPage,[String subPage2]) {
//print("Value change callback");
if(subPage2 == null) {
if(subPage == "A")
isPage1A = value;
else if(subPage == "B")
isPage1B = value;
}
else {
if(subPage2 == "B") {
isPage1A = !value;
isPage1B = value;
}
else if(subPage2 == "A") {
isPage1A = value;
isPage1B = !value;
}
}
notifyListeners();
}
And below is the Page1 widget where the child MaterialApp.router is located :
class Page1 extends StatefulWidget {
Function valueChangeCallback;
Page1(this.valueChangeCallback);
#override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
#override
Widget build(BuildContext context) {
print("Page 1");
return Scaffold(
body: Column(
children: [
InkWell(
onTap: () {
widget.valueChangeCallback(true,"A");
},
child: Text("Move to Sub Pages")
),
Expanded(child: MaterialApp.router(routeInformationParser: NestedAppRouteInformationParser(), routerDelegate: NestedAppRouterDelegate())),
],
),
);
}
}
If you look into app.dart MaterialApp Is a convenience widget that wraps a handful of "widgets that are commonly required for material design applications."
If you were to use the default constructor a top level Navigator object is configured for you.
The MaterialApp.router() is another convenience.
"Creates a [MaterialApp] that uses the [Router] instead of a [Navigator]."
The router constructor provides you a way to create a MaterialApp and configure and return a custom Navigator.
What you are doing, when you use this constructor, is wrapping descendent widgets in all the convenience widgets that MaterialApp has to offer(Including the debug banner).
For Nested Routers what you want to do instead is just use the Router() widget directly, and you will avoid invoking all the extras that MaterialApp affords you during the initialization of your app.
Also of note, there should ideally only be one information parser per app.
as per the notes in router.dart you should pass null to the nester Router Wdiget.
"To opt out of URL updates entirely, pass null for [routeInformationProvider]
/// and [routeInformationParser]. This is not recommended in general, but may be
/// appropriate in the following cases:
///
/// * The application does not target the web platform.
///
/// * **There are multiple router widgets in the application. Only one [Router]
/// widget should update the URL (typically the top-most one created by the
/// [WidgetsApp.router], [MaterialApp.router], or [CupertinoApp.router]).**
///
/// * The application does not need to implement in-app navigation using the
/// browser's back and forward buttons."
class _Page1State extends State<Page1> {
#override
Widget build(BuildContext context) {
print("Page 1");
return Scaffold(
body: Column(
children: [
InkWell(
onTap: () {
widget.valueChangeCallback(true,"A");
},
child: Text("Move to Sub Pages")
),
Expanded(child: Router(routeInformationParser: null, routerDelegate: NestedAppRouterDelegate(), backButtonDispatcher: ChildBackButtonDispatcher(Router.of(context).backButtonDispatcher),)),
],
),
);
}
Also providing the child back button dispatcher as shown will allow you to contact the parent router when executing back button presses...Hope that helps!

How to set a variable value in a widget and in another widget?

I'm trying to set a variable value (number, in the code below) that exists in FirstWidget, from SecondWidget. And notify both widgets so the number will be updated in the two widgets.
class FirstWidget extends StatefulWidget {
#override
_FirstWidgetState createState() => _FirstWidgetState();
}
class _FirstWidgetState extends State<FirstWidget> {
int number = 0;
#override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'$number',
),
SecondWidget(),
Text(
'$number',
)
],
);
}
}
class SecondWidget extends StatefulWidget {
#override
_SecondWidgetState createState() => _SecondWidgetState();
}
class _SecondWidgetState extends State<SecondWidget> {
#override
Widget build(BuildContext context) {
return TextButton(
child: Text('The number is $number. Press to increase the number'),
onPressed: () {
setState(() {
number++;
});
},
);
}
}
(I know that that code gives an error, but the main idea was to give you the problem I want to solve).
The output I want it to be shown:
before pressing the button -
0
The number is 0. Press to increase the number
0
after pressing the button -
1
The number is 1. Press to increase the number
1
So I would be happy if you can help solving this.
Thanks.
There are many approaches to get the result you are looking for, this one is using ValueNotifier in order to change the value of number
Here is an example based on your code:
https://dartpad.dev/b6409e10de32b280b8938aa75364fa7b
We can use another State Management like Provider or Cubit, and we will get the same result.
Another way is to pass a function as a param in the second widget and execute that function when button is pressed