I would like to change the body of HomeScreen from CustomDialog and it is another class. how can I do this ? I tried it in anyways but I can't do this.
this is the main file
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomeScreen(),));
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return SafeArea(child:Column(
children: <Widget>[
Text( Global.number.toString() ),
RaisedButton(child: Text("Click"),
onPressed: (){
showDialog(context: context,builder: (context){
return CustomDialog();
});
},)
],
));
}
}
And this is the Another File to Store global variable
class Global {
static double number = 10.0;
}
And this file is for Dialog
class CustomDialog extends StatefulWidget {
#override
_CustomDialogState createState() => _CustomDialogState();
}
class _CustomDialogState extends State<CustomDialog> {
#override
Widget build(BuildContext context) {
return Dialog(child: FlatButton(
child: Icon(Icons.add_circle,size: 30,),
onPressed: (){
setState(() {
Global.number++;
});
},
),);
}
}
You can pass the setState method of HomeScreen down to CustomDialog. I have shared a full working example based on the code you provided below.
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomeScreen(),));
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
void state() {
setState((){});
}
#override
Widget build(BuildContext context) {
return SafeArea(child:Column(
children: <Widget>[
Text( Global.number.toString() ),
RaisedButton(child: Text("Click"),
onPressed: (){
showDialog(context: context,builder: (context){
return CustomDialog(state);
});
},)
],
));
}
}
class Global {
static double number = 10.0;
}
class CustomDialog extends StatefulWidget {
final Function state;
CustomDialog(this.state);
#override
_CustomDialogState createState() => _CustomDialogState();
}
class _CustomDialogState extends State<CustomDialog> {
#override
Widget build(BuildContext context) {
return Dialog(child: FlatButton(
child: Icon(Icons.add_circle,size: 30,),
onPressed: (){
Global.number++;
widget.state();
},
),);
}
}
As you can see, I create a method parameter for CustomDialog and call that method following the change of Global.number. I created a wrapper to the setState function
void state() {
setState((){});
}
in HomeScreen and passed that method as the parameter to CustomDialog.
The state you set in CustomDialog is, well... the state of the dialog, not of the home screen.
To notify the home screen that some data changed, you can use a ChangeNotifierProvider to provide this data in a common super widget of home screen and the dialog, subscribe the data in the home screen, then access the data in the dialog and change it, then home screen will rebuild automatically.
Please check out Simple app state management for more detail.
Related
For the code below, on the press of the icon of the first class, I want to send data to the second class. First-class just contains the data that needs to pass to the second class. There is no way or not allowed to navigate from first to second class. The only option to navigate to the second class is from the third class. I tried creating a constructor in the second class and implemented
second page(data:_getData.text). But there is no way i am getting the value. I am just getting null.
**First class**
onPressed: () { setState(() => _getData.text);
**SecondPage(data:_getData.text);**
}
**Second class**
class SecondPage extends StatefulWidget {
String? data;
SecondPage({this.data});
#override
_SecondPageState createState() => _SecondPageState(data);
}
class _SecondPageState extends State<SecondPage> {
String? data;
_SecondPageState(this.data);
**Third class**
Get.to(SecondPage)
if you change a lot of states, you would use bloc or any state management. because it is good for the app. if you want only this thing, you use the below code.
First Screen
class FirstScreen extends StatefulWidget {
const FirstScreen({Key? key}) : super(key: key);
#override
State<FirstScreen> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
String title = "no value_f";
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
title = "value";
});
},
child: Text("Press")),
SecondScreen(title: title),
],
),
);
}
}
Second Screen
class SecondScreen extends StatefulWidget {
String title;
SecondScreen({Key? key, required this.title}) : super(key: key);
#override
State<SecondScreen> createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
void initState() {
widget.title = "no value";
super.initState();
}
#override
Widget build(BuildContext context) {
return Text(widget.title);
}
}
I am trying to create an app. I want to change an attribute in a parent class (so it can display a Visibility item, SlidingUpPanel) after submitting a query in the child class (which is a search bar).
I have tried using a callback function and followed How can I pass the callback to another StatefulWidget? but it doesn't seem to do anything when I submit my query in the search bar. Previously, I have also tried to use Navigator.push to call SlidingUpPanel directly but it resulted in a black screen with only SlidingUpPanel.
Parent class (Map):
class MapPage extends StatefulWidget {
const MapPage({Key? key}) : super(key: key);
#override
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
bool IsVisible = false;
void callbackFunction() {
setState(() {
IsVisible = true;
});
}
...
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
...
Visibility(
visible: IsVisible,
child: SlidingUpPanel()),
SearchPage(callbackFunction),
]),
);
}
}
Child class (Search Bar):
class SearchPage extends StatefulWidget {
final Function callback;
SearchPage(this.callback);
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
...
#override
Widget build(BuildContext context) {
return FloatingSearchBar(
...
onSubmitted: (query) {
// callback here, but doesn't seem to do anything
widget.callback;
controller.close();
},
...
);
}
}
To actually call a function (execute it) you must use ().
Try calling the callback function like this:
onSubmitted: (query) {
// use () to actually call the function
widget.callback();
controller.close();
},
i have 3 pages 1,2,3 i want to reach the 3rd page by clicking on a button in the 2nd page that implement a function from the 1st page
so how can i pass the function to the second page
so this is the class that has the function
class SharedPage extends StatefulWidget {
_SharedPageState createState() => _SharedPageState();
}
class _SharedPageState extends State<SharedPage> {
String _information = '';
void updateInformation(String information) {
setState(() => _information = information);
}
void moveToSecondPage() async {
final information = await Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return AddShared(); /// this is the page that i want to reach
}),
);
updateInformation(information);
}
and this is the class that i want to pass the function to
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
var add = [
FlatButton(
shape: CircleBorder(),
child: Icon(
Icons.add,
color: Colors.red,
size: 30,
),
onPressed: () {
/// i want to implement the MoveToSecondScreen here
},
),
];
Hi I'm new to flutter and I have an issue. I created simple app for better explanation. In my main.dart I call Button1() which is in button1.dart. When i press the button it should call Button2() in button2.dart. But the second button is not rendering. How can i do it? And how can i change some data in the button2.dart? For example change text of the button. I set text of the button to some variable and how can i pass it when i click the first button?
Thanks
My main.dart code
import 'package:flutter/material.dart';
import 'button1.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My app"),
),
body: Center(
child: Column(
children: <Widget>[
Button1(),
],
),
),
);
}
}
My button1.dart code
import 'button2.dart';
class Button1 extends StatefulWidget {
#override
_Button1State createState() => _Button1State();
}
class _Button1State extends State<Button1> {
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
RaisedButton(
child: Text("button1"),
onPressed: () {
setState(() {
Button2();
});
},
),
],
),
);
}
}
and here is my button2.dart code
class Button2 extends StatefulWidget {
#override
_Button2State createState() => _Button2State();
}
class _Button2State extends State<Button2> {
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
RaisedButton(
child: Text("Button2"),
onPressed: () {},
),
],
),
);
}
}
I assume you are new to programming and I am trying to explain the concept here as easy as possible..
Let you have your main class (Parent). It contains your two widget/buttons (Children). To pass data from one children to another you can have a variable in the parent class and share your data through it. Here is an example..
class Parent{
String sharedData = "";
bool isVisible = false;
build(context){
//...
Child1((String newData){
setState(() {
sharedData = newData;
isVisible = true;
});
}),
if(isVisible) Child2(sharedData),
}
}
Here Child1 is using a callback to update the data. Inside setState it is updating the Parent class variable and also rebuilding the widget tree. Which updates the Child2 classes data.
Hope you got the point...
I have a parent that contain a listView and a floatingActionButton i would like to hide the floatingActionButton when the user starts scrolling i have managed to do this within the parent widget but this requires the list to be rebuilt each time.
I have moved the floatingActionButton to a separate class so i can update the state and only rebuild that widget the problem i am having is passing the data from the ScrollController in the parent class to the child this is simple when doing it through navigation but seams a but more awkward without rebuilding the parent!
A nice way to rebuild only a child widget when a value in the parent changes is to use ValueNotifier and ValueListenableBuilder. Add an instance of ValueNotifier to the parent's state class, and wrap the widget you want to rebuild in a ValueListenableBuilder.
When you want to change the value, do so using the notifier without calling setState and the child widget rebuilds using the new value.
import 'package:flutter/material.dart';
class Parent extends StatefulWidget {
#override
_ParentState createState() => _ParentState();
}
class _ParentState extends State<Parent> {
ValueNotifier<bool> _notifier = ValueNotifier(false);
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(onPressed: () => _notifier.value = !_notifier.value, child: Text('toggle')),
ValueListenableBuilder(
valueListenable: _notifier,
builder: (BuildContext context, bool val, Widget? child) {
return Text(val.toString());
}),
],
);
}
#override
void dispose() {
_notifier.dispose();
super.dispose();
}
}
For optimal performance, you can create your own wrapper around Scaffold that gets the body as a parameter. The body widget will not be rebuilt when setState is called in HideFabOnScrollScaffoldState.
This is a common pattern that can also be found in core widgets such as AnimationBuilder.
import 'package:flutter/material.dart';
main() => runApp(MaterialApp(home: MyHomePage()));
class MyHomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return HideFabOnScrollScaffold(
body: ListView.builder(
controller: controller,
itemBuilder: (context, i) => ListTile(title: Text('item $i')),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
controller: controller,
);
}
}
class HideFabOnScrollScaffold extends StatefulWidget {
const HideFabOnScrollScaffold({
Key key,
this.body,
this.floatingActionButton,
this.controller,
}) : super(key: key);
final Widget body;
final Widget floatingActionButton;
final ScrollController controller;
#override
State<StatefulWidget> createState() => HideFabOnScrollScaffoldState();
}
class HideFabOnScrollScaffoldState extends State<HideFabOnScrollScaffold> {
bool _fabVisible = true;
#override
void initState() {
super.initState();
widget.controller.addListener(_updateFabVisible);
}
#override
void dispose() {
widget.controller.removeListener(_updateFabVisible);
super.dispose();
}
void _updateFabVisible() {
final newFabVisible = (widget.controller.offset == 0.0);
if (_fabVisible != newFabVisible) {
setState(() {
_fabVisible = newFabVisible;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: widget.body,
floatingActionButton: _fabVisible ? widget.floatingActionButton : null,
);
}
}
Alternatively you could also create a wrapper for FloatingActionButton, but that will probably break the transition.
I think using a stream is more simpler and also pretty easy.
You just need to post to the stream when your event arrives and then use a stream builder to respond to those changes.
Here I am showing/hiding a component based on the focus of a widget in the widget hierarchy.
I've used the rxdart package here but I don't believe you need to. also you may want to anyway because most people will be using the BloC pattern anyway.
import 'dart:async';
import 'package:rxdart/rxdart.dart';
class _PageState extends State<Page> {
final _focusNode = FocusNode();
final _focusStreamSubject = PublishSubject<bool>();
Stream<bool> get _focusStream => _focusStreamSubject.stream;
#override
void initState() {
super.initState();
_focusNode.addListener(() {
_focusStreamSubject.add(_focusNode.hasFocus);
});
}
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
_buildVeryLargeComponent(),
StreamBuilder(
stream: _focusStream,
builder: ((context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData && snapshot.data) {
return Text("keyboard has focus")
}
return Container();
}),
)
],
),
);
}
}
You can use StatefulBuilder and use its setState function to build widgets under it.
Example:
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
int count = 0;
#override
Widget build(BuildContext context) {
return Column(
children: [
// put widget here that you do not want to update using _setState of StatefulBuilder
Container(
child: Text("I am static"),
),
StatefulBuilder(builder: (_context, _setState) {
// put widges here that you want to update using _setState
return Column(
children: [
Container(
child: Text("I am updated for $count times"),
),
RaisedButton(
child: Text('Update'),
onPressed: () {
// Following only updates widgets under StatefulBuilder as we are using _setState
// that belong to StatefulBuilder
_setState(() {
count++;
});
})
],
);
}),
],
);
}
}