Flutter, open the Text displayed inside a Card in an Alert dialog - flutter

in flutter, i'm trying to get the text in the card to be displayed in the Alert Dialog when the card is tapped just like in the pictures below:
image 1
image 2
I merely ask to be pointed in the right direction of how something like this would be acomplished. Although hand-helding would be appreciated, i ask atleast for where to start at.
Thank you in advance!

What I would suggest is having the String for the text of the card stored inside a variable, what you would then do is onTap of the card you call a function that you create and pass the variable that you stored the string of the text is showMyDialog(textVariable) which would call the function to display the dialog and then display the text using the textVariable.
I've attached a more accurate example to achieve what you want.
You can tweak the UI as u wish
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String displayText = "Same Text Everywhere";
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onTap: ()=> showMyDialog(context,displayText),
child: Card(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(displayText),
),
),
)
),
);
}
Future<void> showMyDialog(BuildContext context, String displayText) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text(displayText),
);
},
);
}
}

Related

How to Passing Data from Navigator Pop to Previous Page Where The Data is Used in The Widget Inside the ListView.builder

As stated in the title. How to return data to the previous page where the data is used to list widgets.
I have read this article Flutter Back button with return data or other similar articles. The code works perfectly. But there is a problem if I want to use the data returned to the widget that is in the list.\
Note that I only want to update one ListWidget, I don't want to refresh the state of the entire HomePage like the solution in this article Flutter: Refresh on Navigator pop or go back.
Here is a simple code sample to represent the problem I'm facing.
(check on ListWidget Class and SecondPage Class below)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
HomePage class
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: ListView.builder(
itemCount: 4,
itemBuilder: (_, index){
return ListWidget(number: index+1);
},
)
),
);
}
}
ListWidget Class
class ListWidget extends StatelessWidget{
ListWidget({#required this.number});
final int? number;
String? statusOpen;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () async {
statusOpen = await Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (BuildContext context) => SecondPage(),
),
);
},
child: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(20),
color: Colors.amber,
child: Text(statusOpen != null ? '$number $statusOpen' : '$number Unopened'),
//
// I want to change the text here to 'has Opened' when the user returns from SecondPage
//
),
);
}
}
SecondPage Class
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context, 'has Opened');
// return 'has Opened' to await statusOpen variable
},
child: Text('Go Back'),
),
),
);
}
}
is there any solution to handle this?
If you make your listWidget a stateful widget, then you can get the solution where you just need to call setState when you return to your previous screen. And in this way you will be only changing your single list element and not the full screen.
sample code:
changing this line- class ListWidget extends StatefulWidget
and adding these lines -
onTap: () async {
statusOpen = await Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (BuildContext context) => SecondPage(),
),
);
setState(() {
});
},
If you used the data in your listview just call setstate after Navigator.pop like below code
onTap: () async {
statusOpen = await Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (BuildContext context) => SecondPage(),
),
).then((value) async {
setState(() {});
});
},

'setState' not working in navigated page if custom color is used

For some reason, whenever I navigate to another route using the way described in flutter's documentation i.e https://flutter.dev/docs/cookbook/navigation/navigation-basics, and if I have used custom color in the following way:
color: Color(0xff0e0f26),
in that route, the setState method doesn't work in it. However, if I use color in the following way: color: Colors.blue, the setState method works. I have no idea what is causing this. I want to use a color value that is not present amongst the colors that flutter provides. How do I fix this? The full code along with explanation (using comments) is here:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: homepage(),
);
}
}
class homepage extends StatefulWidget{
#override
_homepageState createState() => _homepageState();
}
class _homepageState extends State<homepage>{
#override
Widget build(BuildContext context){
return Scaffold(
body: Container(
alignment: Alignment.center,
color: Color(0xff0e0f26),
child: RaisedButton(
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
),
)
);
}
}
class SecondRoute extends StatefulWidget{
#override
_SecondRouteState createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute>{
bool test = false;
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("Second"),
),
body: Container(
alignment: Alignment.center,
color: Color(0xff0e0f26), //Here, if I use 'color: Colors.blue', setState works.
child:Column(
children: [
RaisedButton(
onPressed: (){ //When the button is pressed, setState is triggered.
setState((){ //This should theoretically rebuild the widget with 'test' becoming true
//, thus showing the text widget below in the screen, but it doesn't.
test = true;
});
},
),
test ? Text("HELLO"):SizedBox(), //I want 'test' to become true, thus making the text
//widget come on screen.
],
),
),
);
}
}
Thank you.
Your text ist just too dark.
If you use
test ? Text("HELLO", style: TextStyle(color: Colors.white30),):SizedBox(),
it should work. This just makes your text lighter. You should use ElevatedButton instead of RaisedButton, since RaisedButton is deprecated and could cause problems as well.

Flutter Buttons which updates the body

Hello how can I make 2 buttons which will update the body content like tabs. When you click on 1st button it will be shown as selected and the content will change (appBar title, body, slider etc.). When you click to another one It will be shown as selected and will change the content again. But the buttons will appear in both contents. like in this example below
There are look like tabs but the difference is they are changing state and updating the page
Simplest way is to create a global variable which holds the value of the button selected.
Put it out of the main() method.
You can access it from every class and file in your project.
Other ways would require a Provider and state management architecture.
Working sample:
import 'package:flutter/material.dart';
int selectedButton = 0;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Page1(),
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(children: <Widget>[
Text('Page1'),
MyWidget(selectedButton),
])));
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(children: <Widget>[
Text('Page2'),
MyWidget(selectedButton),
])));
}
}
class MyWidget extends StatelessWidget {
final int selected;
MyWidget(this.selected);
#override
Widget build(BuildContext context) {
return Row(children: <Widget>[
RawMaterialButton(
child: Text("Go to page1"),
fillColor: selected == 0 ? Colors.red : Colors.grey,
onPressed: () {
selectedButton = 0;
Navigator.push(
context, MaterialPageRoute(builder: (context) => Page1()));
}),
RawMaterialButton(
child: Text("Go to page2"),
fillColor: selected == 1 ? Colors.red : Colors.grey,
onPressed: () {
selectedButton = 1;
Navigator.push(
context, MaterialPageRoute(builder: (context) => Page2()));
})
]);
}
}

Navigating to another page from drawer menu and setting title to app bar

i am new to flutter and would like someone to help me with code i found in github that i would like to use. take a look at the link below
https://github.com/JohannesMilke/drawer_example
this is an example of a navigational drawer. i like the way the developer coded it and would like to use this example. the problem is that the developer didnt implement navigating to another page. when you click on item in the drawer, it just print a message in the console.
i want to take this a step further. i want to modified the code so that when you click on a item it will navigate to another page and the drawer will b closed. the drawer icon should remain on the toolbar on the new page displayed. also, when you navigate to another page the title of that page should be set in the toolbar.
when i looked at the code , i have an idea where to change but i am not successful. i think i need to change the body tag at the bottom of the code. the problem is that i dont know how to call the DrawerWidgetState class in drawer_widget.dart file.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final String appTitle = 'Ttitle';
#override
Widget build(BuildContext context) => MaterialApp(
title: appTitle,
theme: ThemeData(
primaryColor: Colors.red,
textTheme: TextTheme(
subhead: TextStyle(
color: Colors.black.withOpacity(0.4),
),
),
dividerColor: Colors.black.withOpacity(0.4),
),
home: MainPage(appTitle: appTitle),
);
}
class MainPage extends StatefulWidget {
final String appTitle;
const MainPage({this.appTitle});
#override
MainPageState createState() => MainPageState();
}
class MainPageState extends State<MainPage> {
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(widget.appTitle),
),
drawer: DrawerWidget(),
body: container()
);
}
i define the following function in drawer_widget.dart file
getDrawerItemWidget(int pos) {
print('testing');
switch (pos) {
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
case 2:
return new ThirdFragment();
default:
return new Text("Error");
}
}
but i dont know how to call it from Mainpage Body tag and set title accordingly. can someone help modify the code so that i can nagivate to another page and set title? full code is in
https://github.com/JohannesMilke/drawer_example
thanks in advance
Using the drawer_example library you need to make some small changes in order to make it work.
Over your drawer_widget.dart add this add the beginning:
typedef TitleCallback = void Function(String, int);
Once you do that, your Drawer StatefulWidget should looks this way:
class DrawerWidget extends StatefulWidget {
final TitleCallback callback;
final int tabIndex;
#override
DrawerWidgetState createState() => DrawerWidgetState();
DrawerWidget(this.callback, this.tabIndex);
}
and your initState:
#override
void initState() {
selectedDrawerIndex = widget.tabIndex;
selectedProfileIndex = 0;
super.initState();
}
This will be the constructor to pass the new value back to your main.dart file.
Inside the ListTile, you can add the following logic:
ListTile(
leading: Icon(item.icon),
title: Text(item.name),
selected: selectedDrawerIndex == currentIndex,
onTap: () {
final item = getOffsetIndex(drawerGroups, currentIndex);
print('Selected index $selectedDrawerIndex with name ${item.name}');
setState(() {
selectedDrawerIndex = currentIndex;
widget.callback(item.name, selectedDrawerIndex);
});
Navigator.pop(context); // to close the Drawer
},
)
If you can check, the line: widget.callback(item.name); sends the tab name over the callback and that logic can be applied any where you want to change your title. It can even be a hard coded title like:
widget.callback("Second Tab");
Now, going back to your main.dart file:
class MyApp extends StatefulWidget {
final String title;
ListExample(this.title);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Widget> _fragments = <Widget> [
Container(
child: Text("Fragment One"),
),
Container(
child: Text("Fragment Two"),
),
Container(
child: Text("Fragment Three"),
),
];
String titleAppBar = "Testing";
int tabIndex = 0;
#override
void initState() {
setState(() {
titleAppBar = widget.title;
});
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: widget.title,
home: Scaffold(
appBar: AppBar(
title: Text(titleAppBar),
),
drawer: DrawerWidget((title, index) {
setState(() {
titleAppBar = title;
tabIndex = index;
});
}, tabIndex),
body: _fragments[tabIndex],
),
);
}
}
Final Result:
Looking at the example on GitHub, it's overcomplicating something that's too easy with Flutter.
Here's a simple example on how to use a Drawer on Flutter:
main.dart
import 'package:flutter/material.dart';
import 'another_page.dart';
import 'home_page.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// declaring your routes will allow you to push and remove everything from the stack (including the drawer) with pushNamedAndRemoveUntil()
routes: {
'home': (context) => HomePage(),
'anotherPage': (context) => AnotherPage(),
},
initialRoute: 'home',
);
}
}
home_page.dart (another_page.dart is exactly the same for illustration purpose)
import 'package:flutter/material.dart';
import 'menu_drawer.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: MenuDrawer(),
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Text('Home'),
),
);
}
}
menu_drawer.dart
import 'package:flutter/material.dart';
class MenuDrawer extends StatelessWidget {
// Push the page and remove everything else
navigateToPage(BuildContext context, String page) {
Navigator.of(context).pushNamedAndRemoveUntil(page, (Route<dynamic> route) => false);
}
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
// This could be mapped from a List of items
children: <Widget>[
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => navigateToPage(context, 'home'),
),
ListTile(
leading: Icon(Icons.panorama),
title: Text('Another page'),
onTap: () => navigateToPage(context, 'anotherPage'),
),
],
),
);
}
}
Final result:

How to do Navigator.popUntil properly when using different animations for each push

I am trying to rebuild iOS app in Flutter, but facing a problem with navigation.
Here what I am trying to do:
List of Added Exchange Pairs with Add button (A screen)
Add button opens Picker with Exchanges (B screen) with transition from bottom to top.
By tapping on exchange it pushes new Picker with Pairs (C
screen) with transition from right to left.
when user taps on pair it closes all pickers at once and deliver result of picking to A screen.
I have tried double pop and popUntil but result always same, I see 2 back transitions (left to right and top to bottom) at same time.
How it looks in iOS native app:
How it looks in Flutter app:
Solved with nested Navigator
Wrapped Screen B with Navigator and used this navigator to push screen C, on screen C used root navigator to pop. Result is below:
Here the example of how I solved it:
import 'package:flutter/material.dart';
void main() {
MaterialPageRoute.debugEnableFadingRoutes = true;
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _result = "--";
void _openSubscreen() {
Navigator.of(context).push<String>(
new MaterialPageRoute(
settings: RouteSettings(name: '/subscreen'),
builder: (context) => SubScreen(),
),
).then((result) => setState((){
_result = result;
}));
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'Result from navigator:',
),
new Text(
_result,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline,
),
SizedBox(height: 32.0,),
OutlineButton(
onPressed: _openSubscreen,
child: Text('Start flow'),
),
],
),
),
);
}
}
class SubScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: new Navigator(
onGenerateRoute: (routeSettings) {
final path = routeSettings.name;
if (path == '/') {
return new MaterialPageRoute(
settings: routeSettings.copyWith(isInitialRoute: true),
builder: (_) => SubScreenPage1(),
);
} else if (path == '/nexpage') {
return new MaterialPageRoute(
settings: routeSettings,
builder: (_) => SubScreenPage2(),
);
}
},
),
);
}
}
class SubScreenPage1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Center(
child: OutlineButton(
child: Text('Next sub page!'),
onPressed: () {
Navigator.of(context).pushNamed('/nexpage');
},
),
);
}
}
class SubScreenPage2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Center(
child: OutlineButton(
child: Text('Deliver result!'),
onPressed: () {
final date = DateTime.now().toString();
Navigator
.of(context, rootNavigator: true)
.pop('Delivered at $date');
},
),
);
}
}
When you build your MaterialApp by setting home: and routes: you can achieve "pop to root" without hardcoding what route to pop until by;
Navigator.popUntil(
context,
ModalRoute.withName(Navigator.defaultRouteName),
);
Because Navigator.defaultRouteName will be set to whatever you set home: to.
Going a bit off-topic but, this is especially nice if you have "variable" home screen, as in using a FutureBuilder to decide what will be the home screen. For example, if you are showing a splash screen until you are loading the initial state from disk.
home: isUserLoggedIn
? HomePage()
: FutureBuilder(
future: () async {
print('Initializing');
print('Waiting For NoReason');
await Future.delayed(const Duration(seconds: 1));
print('Initialization Complete');
}(),
builder: (_, snap) {
if (snap.connectionState == ConnectionState.waiting) {
return SplashPage();
} else {
return LogInPage();
}
},
),