this is my second class
class SecondClass extends StatefulWidget {
_SecondClassState createState() => _SecondClassState();
}
class _SecondClassState extends State<SecondClass> {
#override
Widget build(BuildContext context) {
Return Container(
RaisedButton(
onPressed: Navigator.of(context).pop('lorem ipsum),
child: Text('Back and get data')
)
);
}
}
this is my first class
class FirstClass extends StatefulWidget {
_FirstClassState createState() => _FirstClassState();
}
class _FirstClassState extends State<FirstClass> {
#override
Widget build(BuildContext context) {
Return Container(
// show data here
);
}
}
How to get string of lorem ipsum and display it in first class, where I should put the code to get that string?
You can see in the screenshot, whatever item is clicked in 2nd screen, it is sent back to page 1 and Button shows the same item.
Here is the full code for a basic implementation.
void main() {
runApp(MaterialApp(home: Page1()));
}
class Page1 extends StatefulWidget {
#override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
String _response = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1")),
body: Center(
child: RaisedButton(
child: Text("Go to Page 2"),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => Page2())).then((value) {
setState(() {
_response = value; // you receive here
});
});
},
),
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2")),
body: ListView.builder(
itemCount: 20,
itemBuilder: (c, i) {
return ListTile(
title: Text("Item ${i}"),
onTap: () {
Navigator.pop(context, "Item ${i}"); // what you pass here
},
);
},
),
);
}
}
Navigator.of(context).push(MaterialPageRoute(builder: (context) => SecondClass())).then((value) {
// value is lorem ipsum
});
You should use this in your FirstClass when you are navigating to the SecondClass.
Full solution:
class _FirstClassState extends State<FirstClass> {
String _string = "";
#override
Widget build(BuildContext context) {
return RaisedButton(
child: Text("Go"),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => SecondClass())).then(
(value) {
setState(() {
_string = value; // lorem ipsum
});
},
);
},
);
}
}
Related
in ios, if I swipe starting from the left of the screen and fall towards the center it goes back from the view. now I wanted to replicate the same thing in Flutter to my app, as I have the top left button to go back classic, but I would also like to have the ios style where you can go back even by swiping from the left. how can I do ?
Check out this example that i have created using the Gesture detector:
You can use this widget at the top of the page so that it can detect the swipes
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FlatButton(
child: Text("Next Page"),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => SecondPage()));
},
),
),
);
}
}
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(onHorizontalDragUpdate: (details) {
// Note: Sensitivity is integer used when you don't want to mess up vertical drag
int sensitivity = 8;
if (details.delta.dx > sensitivity) {
// Right Swipe
} else if (details.delta.dx < -sensitivity) {
//Left Swipe
Navigator.of(context).pop();
}
}
),
);
}
}
Let me know this is what you are trying to implement
tried this and works, on screen 1 you're navigating from add this line on your gesture detector.
onHorizontalDragUpdate: (details) {
if (details.delta.direction > 0) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Page2()));
}
},
On Page 2, on build context, add this line
onVerticalDragUpdate: (details) {},
onHorizontalDragUpdate: (details) {
if (details.delta.direction <= 0) {
Navigator.pop(context);
}
},
Full code snippet below
import 'package:flutter/material.dart';
import 'package:swipe_detection_example/page2.dart';
class Page1 extends StatelessWidget {
const Page1({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onVerticalDragUpdate: (details) {},
onHorizontalDragUpdate: (details) {
if (details.delta.direction > 0) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Page2()));
}
},
child: Scaffold(
body: Center(
child: Text('Page 1'),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:swipe_detection_example/page2.dart';
class Page2 extends StatelessWidget {
const Page2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onVerticalDragUpdate: (details) {},
onHorizontalDragUpdate: (details) {
if (details.delta.direction <= 0) {
Navigator.pop(context);
}
},
child: Scaffold(
body: Center(
child: Text('Page 2'),
),
),
);
}
}
I have an AppBar in main.dart and I want to defined it as primary on it's child, But I want to change the title of AppBar itself when I'm on child's page, how can i do that properly?
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter App",
theme: ThemeData(
primaryColor: Colors.cyan,
brightness: Brightness.dark
),
home: Scaffold(
appBar: AppBar(
title: Text("Main Dart"),
),
body: HomeScreen(),
),
routes: <String, WidgetBuilder>{
'/homeScreen': (buildContext)=>HomeScreen(),
'/second': (buildContext)=>Second()
},
);
}
}
//HomeScreen or Second Widget on different dart file
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
//here I want to change the title of Main Dart to HomeScreen
return Container(
child: Center(
child: FlatButton(
child: new Text("Home screen"),
onPressed: (){
Route route = MaterialPageRoute(builder: (context) => Second());
Navigator.push(context, route);
},
),
),
);
}
}
or I need to put Scaffold(appBar:AppBar(...), ...) in every screen? it is the best approach?
Have a BLoC for app properties in app_properties_bloc.dart
final appBloc = AppPropertiesBloc();
class AppPropertiesBloc{
StreamController<String> _title = StreamController<String>();
Stream<String> get titleStream => _title.stream;
updateTitle(String newTitle){
_title.sink.add(newTitle);
}
dispose() {
_title.close();
}
}
Use stream builder in AppBar like this:
AppBar(
title: StreamBuilder<Object>(
stream: appBloc.titleStream,
initialData: "Main Dart",
builder: (context, snapshot) {
return Text(snapshot.data);
}
),
),
Use this to update title on button's onPressed()
onPressed: () {
appBloc.updateTitle('new title');
},
Just in case you are changing only the title of Scaffold then this will work.
I am creating a DefaultScaffold with the title each screen provides. Here the code will show the MainPage and two other pages which have the same AppBar with changed titles.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(initialRoute: 'home', routes: <String, WidgetBuilder>{
'home': (context) => SOMain(),
'/secondPage': (context) => DefaultScaffold("Second Screen", SOSecond()),
'/thirdPage': (context) => DefaultScaffold("Third Screen", SOThird()),
});
}
}
class DefaultScaffold extends StatelessWidget {
String title;
Widget body;
DefaultScaffold(this.title, this.body);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: body,
);
}
}
class SOMain extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultScaffold(
"Main Screen",
Center(
child: RaisedButton(
child: Text("Go to second screen"),
onPressed: () {
Navigator.pushNamed(context, '/secondPage');
}),
),
);
}
}
class SOSecond extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("Go the 3rd screen"),
onPressed: () => Navigator.pushNamed(context, "/thirdPage"),
),
);
}
}
class SOThird extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(child: Text("You are on last screen"));
}
}
Note: This is a simple workaround and may not be the best way to do this.
You can accomplish updating the state of the parent from a child by using a callback function.
Parent Class:
import 'package:flutter/material.dart';
class Parent extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return ParentState();
}
}
class ParentState extends State<Parent> {
String title = "Old Title";
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(title),
),
body: DaysFragmentView(onTitleSelect: (String value) {
setTitle(value);
}
),
);
}
void setTitle(String value) {
setState(() {
title = value;
});
}
}
Child Class
typedef TitleCallback = void Function(Title color);
class DaysFragmentView extends StatelessWidget {
const DaysFragmentView({this.onTitleSelect});
final TitleCallback onTitleSelect;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
RaisedButton(
child: Text('One'),
onPressed: () {
onTitleSelect("TITLE ONE");
},
),
RaisedButton(
child: Text('Two'),
onPressed: () {
onTitleSelect("TITLE TWO");
},
)
],
);
}
}
Reference:
call-method-in-one-stateful-widget-from-another-stateful-widget-flutter
working-with-callback-in-flutter
Using ValueListenableBuilder is an option.
Use an instance variable
String appTitle;
Then set the app bar as in the following block:
appBar: AppBar(
ValueListenableBuilder<String>(
valueListenable: appTitle,
builder: (context, value, child) {
return Text(appTitle.value);
},
),
After that you can simply set appTitle.value in the other class. The title will be changed too because it listens to that value.
appTitle.value = "Home Screen";
Some answer here are too complicated. Here is a full working example using app bar update from child with scafold widget.
You can run the example in dart pad
import 'package:flutter/material.dart';
void main() {
runApp(const MyHomePage(title: 'init title'));
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ValueNotifier<String?> _appBarTitleNotifier = ValueNotifier<String?>(null);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: ValueListenableBuilder<String?>(
builder: (BuildContext context, String? value, Widget? child) {
return Text(value ?? widget.title);
},
valueListenable: _appBarTitleNotifier,
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ChildDemoTitleBar(titleNotifier: _appBarTitleNotifier)
],
),
),
),
);
}
}
class ChildDemoTitleBar extends StatefulWidget {
final ValueNotifier<String?> titleNotifier;
const ChildDemoTitleBar({Key? key, required this.titleNotifier})
: super(key: key);
#override
State<ChildDemoTitleBar> createState() => _ChildDemoTitleBarState();
}
class _ChildDemoTitleBarState extends State<ChildDemoTitleBar> {
int _counter = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: InkWell(
onTap: () {
_counter++;
widget.titleNotifier.value = "title updated $_counter";
},
child: const Text("tap to update title")));
}
}
I am developing a stateful widget and I did not yet understand the difference between useing setState and a normal variable assignment.
This is the code I am useing:
import ...
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
String _state_var;
#override
void initState() {
super.initState();
setState(() {
_state_var = "test";
});
}
#override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppState>(
converter: (store) => store.state,
builder: (context, appState) {
return Scaffold(
appBar: AppBar(
title: Text("TITLE"),
),
body: Container(
padding: EdgeInsets.all(10.0),
child: ListView(
children: [
Text(_state_var),
Center(
child: FlatButton(
child: Text('CHANGE VALUE'),
onPressed: () async {
_state_var = "SND TEST";
// OR
setState(() {
_state_var = "SND TEST";
});
},
),
),
])
),
);
},
);
}
}
Whats the difference between:
_state_var = "SND TEST";
and
setState(() {
_state_var = "SND TEST";
});
I mean, in both cases the Text gets new value.
I'm using the Flutter UserAccountsDrawerHeader widget to display the user's data but I could not figure out how to implement the onDetailsPressed() function to call the user details. Here is my code:
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return new Scaffold(
drawer: _buildDrawer(context),
appBar: _buildAppBar(),
);
}
}
Widget _buildAppBar() {
return new AppBar();
}
Widget _buildDrawer(BuildContext context) {
return new Drawer(
child: new ListView(
children: <Widget>[
new UserAccountsDrawerHeader(
accountName: new Text("Cleudice Santos"),
accountEmail: new Text("cleudice.ms#gmail.com"),
onDetailsPressed: () {},
),
new ListTile(
title: new Text("Visão geral"),
leading: new Icon(Icons.dashboard),
onTap: () {
print("Visão geral");
},
),
],
),
);
}
I want to click the arrow and show the account details as shown below. That is, overlapping the content of the drawer. As the Gmail app does.
Basically, what you should be doing is replacing the rest of the content with user details rather than the current list. The simplest way to do this is to make your drawer into a stateful widget and have a boolean that keeps track of whether user details or the normal list should be shown.
I've added that to your code (and added a bit to make it self-contained so you can paste it to a new file to test out):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: UserDetailDrawer(),
appBar: _buildAppBar(),
);
}
}
Widget _buildAppBar() {
return AppBar();
}
class UserDetailDrawer extends StatefulWidget {
#override
_UserDetailDrawerState createState() => _UserDetailDrawerState();
}
class _UserDetailDrawerState extends State<UserDetailDrawer> {
bool showUserDetails = false;
Widget _buildDrawerList() {
return ListView(
children: <Widget>[
ListTile(
title: Text("Visão geral"),
leading: Icon(Icons.dashboard),
onTap: () {
print("Visão geral");
},
),
ListTile(
title: Text("Another tile??"),
leading: Icon(Icons.question_answer),
),
],
);
}
Widget _buildUserDetail() {
return Container(
color: Colors.lightBlue,
child: ListView(
children: [
ListTile(
title: Text("User details"),
leading: Icon(Icons.info_outline),
)
],
),
);
}
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(children: [
UserAccountsDrawerHeader(
accountName: Text("Cleudice Santos"),
accountEmail: Text("cleudice.ms#gmail.com"),
onDetailsPressed: () {
setState(() {
showUserDetails = !showUserDetails;
});
},
),
Expanded(child: showUserDetails ? _buildUserDetail() : _buildDrawerList())
]),
);
}
}
Complete newbie, so bear with me. Just a question on how I could refactor my code using the DRY principle. I'm sure it can be done on such a simple example so here goes.... My code below shows three 'switchListTiles'. I've managed to work out how to create 3 switchListTiles on top of one another, and also how to get them to turn on/off individually. Its just that this means I'm creating the following function 3 times:
bool _value3 = false;
void _onChanged3(bool value3) {
setState(() {
_value3 = value3;
});
}
I'm sure there is a way I could change this so I don't have the same code three times.
Any help would be greatly appreciated
Many thanks in advance
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "Switch Widget Demo",
home: new MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _value = false;
void _onChanged(bool value) {
setState(() {
_value = value;
});
}
bool _value2 = false;
void _onChanged2(bool value2) {
setState(() {
_value2 = value2;
});
}
bool _value3 = false;
void _onChanged3(bool value3) {
setState(() {
_value3 = value3;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Switch Demo"),
backgroundColor: Colors.redAccent,
centerTitle: true,
),
body: Container(
padding: EdgeInsets.all(32.0),
child: Column(
children: <Widget>[
Switch(value: _value,
onChanged: (bool value) {_onChanged(value);}),
SwitchListTile(value: _value,
title: Text("Click Me"),
activeColor: Colors.red,
secondary: Icon(Icons.home),
subtitle: Text("For my small print"),
onChanged: (bool value) {_onChanged(value);}),
SwitchListTile(value: _value2,
title: Text("Click Me Again Please"),
activeColor: Colors.lightGreen,
secondary: Icon(Icons.perm_identity),
onChanged: (bool value2) {_onChanged2(value2);}),
SwitchListTile(value: _value3,
title: Text("And Again Please"),
activeColor: Colors.blueGrey,
subtitle: Text("Some more small print"),
secondary: Icon(Icons.person),
onChanged: (bool value) {_onChanged3(value);}),
],
),
),
);
}
}
You just need to refactor the SwitchListTiles into its separate class, then make List<SwitchListTiles> in the parent widget.
Here I create 20 of them with lesser code:
class MySwitchListTilesContainer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[800],
body: ListView(
children: List.generate(20, (i)=>MySwitchListTile(
)),
),
);
}
}
class MySwitchListTile extends StatefulWidget {
#override
_MySwitchListTileState createState() => new _MySwitchListTileState();
}
class _MySwitchListTileState extends State<MySwitchListTile> {
bool _v = false;
#override
Widget build(BuildContext context) {
return SwitchListTile(
value:_v,
onChanged: (value)=>setState((){
_v=value;
}),
);
}
}