Flutter-Not able to load Widget from StreamBuilder - dart

I am calling API using BLoC. On successful response, I need to call Widget named
_moveToHomeScreen()
.
Following is my code for that
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
//body: UserDetail(),
body: new Container(
padding: EdgeInsets.all(16.0),
child:StreamBuilder(
stream: bloc.validateUser,
builder: (BuildContext context, snapshot) {
if(snapshot.hasData){
_moveToHomeScreen();
}
return Column(
children: <Widget>[
_createInputFields(),
_createRegisterButton(),
],
);
}
),
);
}
AND
Widget _moveToHomeScreen () {
print('inside move to home screen');
return Center(
child: Opacity(
opacity: 0.5,
child: Text(
"Save a person to see them here!",
key: Key("Placeholder"),
),
),
);
}
Control goes into the Widget but I am not able to see desired output from Widget.

Your Streambuilder never returns _moveToHomeScreen();
override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
//body: UserDetail(),
body: new Container(
padding: EdgeInsets.all(16.0),
child:StreamBuilder(
stream: bloc.validateUser,
builder: (BuildContext context, snapshot) {
if(snapshot.hasData){
return _moveToHomeScreen();
}
return Column(
children: <Widget>[
_createInputFields(),
_createRegisterButton(),
],
);
}
),
);
}
Just added return before _moveToHomeScreen();

Related

How to implement dynamic widget routing in Flutter?

I'm adding routing into my Flutter app and I would like to re-use some common Widgets across all of my routes.
For instance, the AppBar and Drawer instances should be defined on the top level view and the routed view should be in a contained Widget (the yellow part in the image)
Is is supported? currently all "Flutter Routing" references I find demonstrate replacement of the entire view => different instances of the common Widgets for every route.
void redirect(BuildContext context, name) {
Navigator.of(context).pushNamed(name);
}
getCommonDrawer(context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('header'),
decoration: BoxDecoration(
color: Colors.greenAccent,
),
),
ListTile(
title: Text('foo'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
title: Text('bar'),
onTap: () {
Navigator.pop(context);
},
),
],
),
);
}
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Screen 1"),
),
drawer: getCommonDrawer(context),
body: new Center(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new RaisedButton(
onPressed: () {
redirect(context, "/screen2");
},
child: new Text("screen2"),
)
],
),
),
);
}
}
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Screen 2"),
),
drawer: getCommonDrawer(context),
body: new Center(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
new RaisedButton(
onPressed: () {
redirect(context, "/screen1");
},
child: new Text("screen1"),
)
],
),
),
);
}
}
void main() { // 1
runApp( // 2
new MaterialApp( //3
home: new Screen1(), //4
routes: <String, WidgetBuilder> { //5
'/screen1': (BuildContext context) => new Screen1(), //6
'/screen2' : (BuildContext context) => new Screen2() //7
},
)
);
}

Flutter Stack with CircularProgressIndicator and GridView widgets, does nor work propertly

I have a Stack widget as follows:
Widget build(BuildContext context) {
final title = StringsES.title_meter_list_screen;
_context = context;
return Scaffold(
appBar: appbar,
body: Stack(
children: <Widget>[
GridView.count(
padding: EdgeInsets.all(10.0),
primary: false,
crossAxisCount: 2,
children: _buildWidgetList(),
),
Align(
child: _progressBarWidget(),
),
],
)
);
}
And the _progressBarWidget is the following:
Widget _progressBarWidget() {
return (_isProgressBarVisible)
? CircularProgressIndicator(strokeWidth: 4.0, )
: Container();
}
In this way, the CircularProgressIndicator Widget is displayed behind the GridView, and I want it to appear in front of the GridView.
If I change my code and replace the CircularProgressIndicator with a simple text widget, it works correctly.
What am I doing wrong?

Flutter dart add list to children

I am new on dart, I just want to add a list of my data using map (store.state.availablePage.map) to the children of ListView, but I already have some item on the ListView.
Here the sample code I want :
class MgDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StoreBuilder<AppState>(
builder: (context, store) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
Text("Title"),
store.state.availablePage.map((value) {
return ListTile(
title: Text("Title"),
onTap: () {},
);
}).toList(),
],
),
);
},
);
}
}
Please help me how I can achieve that?
Update: the code above is not compiled.
Updates Dart Lang version > 2.2.2, can be achieve using below code :
class MgDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StoreBuilder<AppState>(
builder: (context, store) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
Text("Title"),
...store.state.availablePage.map((value) {
return ListTile(
title: Text("Title"),
onTap: () {},
);
}).toList(),
],
),
);
},
);
}
}
You ListView is having Text(Widget) and a Array of ListTile(Array of Widgets) which means ListView(children: [Widget, [Widget]]).
But it should be ListView(children: [Widget1, Widget2, Widget3,...]). Below code might help
class MgDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StoreBuilder<AppState>(
builder: (context, store) {
List<Widget> list = store.state.availablePage.map((value) {
return ListTile(
title: Text("Title"),
onTap: () {},
);
}).toList();
list.insert(0, Text("Title"));
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: list,
),
);
},
);
}
}
If for some reason someone is unable to use "..." operator, there is also another solution. It is not as elegant as "..." operator, but it also works.
You can just use ..addAll(list) at the end of the list.
Here is how it would look like in given example:
class MgDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StoreBuilder<AppState>(
builder: (context, store) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
Text("Title"),
]..addAll(store.state.availablePage.map((value) {
return ListTile(
title: Text("Title"),
onTap: () {},
);
}).toList(),),
),
);
},
);
}
}

How to make a full screen dialog in flutter?

I want to make a full screen dialog box. Dialog box background must be opaque.
Here is an example:
How to make like this in Flutter?
You can use the Navigator to push a semi-transparent ModalRoute:
import 'package:flutter/material.dart';
class TutorialOverlay extends ModalRoute<void> {
#override
Duration get transitionDuration => Duration(milliseconds: 500);
#override
bool get opaque => false;
#override
bool get barrierDismissible => false;
#override
Color get barrierColor => Colors.black.withOpacity(0.5);
#override
String get barrierLabel => null;
#override
bool get maintainState => true;
#override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
// This makes sure that text and other content follows the material style
return Material(
type: MaterialType.transparency,
// make sure that the overlay content is not cut off
child: SafeArea(
child: _buildOverlayContent(context),
),
);
}
Widget _buildOverlayContent(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'This is a nice overlay',
style: TextStyle(color: Colors.white, fontSize: 30.0),
),
RaisedButton(
onPressed: () => Navigator.pop(context),
child: Text('Dismiss'),
)
],
),
);
}
#override
Widget buildTransitions(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
// You can add your own animations for the overlay content
return FadeTransition(
opacity: animation,
child: ScaleTransition(
scale: animation,
child: child,
),
);
}
}
// Example application:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Playground',
home: TestPage(),
);
}
}
class TestPage extends StatelessWidget {
void _showOverlay(BuildContext context) {
Navigator.of(context).push(TutorialOverlay());
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Test')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: RaisedButton(
onPressed: () => _showOverlay(context),
child: Text('Show Overlay'),
),
),
),
);
}
}
Well here is my implementation which is quite straightforward.
from first screen
Navigator.of(context).push(PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) =>
RedeemConfirmationScreen()));
at 2nd screen
class RedeemConfirmationScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.85), // this is the main reason of transparency at next screen. I am ignoring rest implementation but what i have achieved is you can see.
.....
);
}
}
and here are the results.
Screenshot (Flutter's native dialog)
Call this method to show the dialog in fullscreen.
showGeneralDialog(
context: context,
barrierColor: Colors.black12.withOpacity(0.6), // Background color
barrierDismissible: false,
barrierLabel: 'Dialog',
transitionDuration: Duration(milliseconds: 400),
pageBuilder: (_, __, ___) {
return Column(
children: <Widget>[
Expanded(
flex: 5,
child: SizedBox.expand(child: FlutterLogo()),
),
Expanded(
flex: 1,
child: SizedBox.expand(
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Dismiss'),
),
),
),
],
);
},
);
Note: This answer does not discuss making the modal transparent, but is an answer is for the stated question of "How to make a full screen dialog in flutter?". Hopefully this helps other that find this question through a search like I did, that don't need a transparent modal.
Create your modal dialog class:
class SomeDialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text('Dialog Magic'),
),
body: new Text("It's a Dialog!"),
);
}
}
In the class that needs to open the dialog, add something like this:
void openDialog() {
Navigator.of(context).push(new MaterialPageRoute<Null>(
builder: (BuildContext context) {
return new SomeDialog();
},
fullscreenDialog: true));
}
If fullscreenDialog above is true, then the app bar will have an "x" close button. If false, it will have a "<-" back arrow.
If you need to get the result of a dialog action, add a button to your dialog that returns a value when popping the navigation stack. Something like this:
onPressed: () {
Navigator
.of(context)
.pop(new MyReturnObject("some value");
}
then in your class opening the dialog, do capture the results with something like this:
void openDialog() async {
MyReturnObject results = await Navigator.of(context).push(new MaterialPageRoute<MyReturnObject>(
builder: (BuildContext context) {
return new SomeDialog();
},
fullscreenDialog: true));
}
You can use showGeneralDialog method with any widget extends from Material like Scaffold, Card, ..etc.
For example I am going to it with Scaffold like this:
showGeneralDialog(
context: context,
pageBuilder: (context, animation, secondaryAnimation) => Scaffold(
backgroundColor: Colors.black87,
body: //Put your screen design here!
),
);
And now you can set your design as a normal screen by using Scaffold.
Note: if you want to go back you can Navigator like this:
Navigator.of(context).pop(null)
Different ways to show fullscreen dialog
A. Material Dialog
showDialog<void>(
context: context,
useSafeArea: false,
builder: (BuildContext context) {
return const SomeScaffoldView();
},
);
B. Cupertino Dialog
showCupertinoDialog<void>(
context: context,
builder: (BuildContext context) {
return const SomeScaffoldView();
},
);
C. Custom Dialog
Flutter uses this under-the-hood when displaying dialogs.
Can customize transition animation with transitionBuilder, here's a random guide with example animations.
showGeneralDialog(
context: context,
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return const SomeScaffoldView();
},
);
Sample Scaffold View used in above snippets.
class SomeScaffoldView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample Fullscreen Dialog'),
),
body: const Center(child: Text('Dialog Body')),
);
}
}
You can use AlertDialog with zero insetPadding like below:
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(builder: (context, setState) {
return AlertDialog(
insetPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))),
content: SizedBox.expand(
child: Column(
children: <Widget>[
SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Wrap(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 1,
child: Text(
"Sample type",
style: TextStyle(fontWeight: FontWeight.w700),
),
),
Expanded(flex: 1, child: Text(""))
],
),
],
)),
],
),
));
});
},
);
RFlutter Alert is super customizable and easy-to-use alert/popup dialogs for Flutter. You may create reusable alert styles or add buttons as much as you want with ease.
Alert(context: context, title: "RFLUTTER", desc: "Flutter is awesome.").show();
RFlutter
It's easy to use! :)
you can do like this if you use popular flutter library getx
getx link
void showAlertDialogg(
String body,
String? confirmButtonText,
String? cancelButtonText,
Function(bool onConfirm, bool onCancel) clickEvent,
{barrierDismissible = false}) {
Get.dialog(
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextComponent(
body,
textAlign: TextAlign.center,
fontSize: textSmallFontSize,
fontWeight: titleFontWeight,
color: Colors.white,
),
Row(
//crossAxisAlignment : CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: OutlineButtonComponent(
text: cancelButtonText,
borderColor: kPrimaryColor,
onPressed: () {
Get.back();
clickEvent(false, true);
},
textColor: kPrimaryColor,
padding: EdgeInsets.fromLTRB(16, 16, 8, 16),
),
),
Expanded(
flex: 1,
child: ButtonComponent(
text: confirmButtonText,
buttonColor: kPrimaryColor,
onPressed: () {
Get.back();
clickEvent(true, false);
},
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(8, 16,16, 16),
),
),
],
)
],
),
barrierColor: Colors.black12.withOpacity(0.8),
useSafeArea: true
);
}
you can pas params as you want & call this method where you need it. it supports widget so you can setup the widget as you want.
Wrap your top-level widget with Navigator widget like so:
return Navigator(
pages: [
MaterialPage(
child: MainScreen(
child: widgets...
then call showDialog and because useRootNavigator is set to true in default it will use the root navigator that we added above the MainScreen

Flutter Access parent Scaffold from different dart file

I have this:
final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
key: _scaffoldkey,
drawer: Menu(),
appBar: AppBar(
title: Container(
child: Text('Dashboard'),
),
bottom: TabBar(
tabs: <Widget>[
...
],
),
),
body: TabBarView(
children: <Widget>[
...
],
),
),
);
}
}
Now, the drawer: Menu() is imported from another menu.dart file, which looks like this:
class Menu extends StatelessWidget {
final GlobalKey<ScaffoldState> drawerKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return new Drawer(
key: drawerKey,
child: new ListView(
children: <Widget>[
new ListTile(
dense: true,
title: new Text('My Text'),
onTap: () {
// On tap this, I want to show a snackbar.
scaffoldKey.currentState.showSnackBar(showSnack('Error. Could not log out'));
},
),
],
),
);
}
}
With the above approach, I get
NoSuchMethodError: The method 'showSnackBar' was called on null.
An easy solution is to tuck the entire menu.dart contents in the drawer: ... directly.
Another way I'm looking at is being able to reference the parent scaffold in order to display the snackbar.
How can one achieve that?
Why can't one even just call the snackbar from anywhere in Flutter and compulsorily it has to be done via the Scaffold? Just why?
You should try to avoid using GlobalKey as much as possible; you're almost always better off using Scaffold.of to get the ScaffoldState. Since your menu is below the scaffold in the widget tree, Scaffold.of(context) will do what you want.
The reason what you're attempting to do doesn't work is that you are creating two seperate GlobalKeys - each of which is its own object. Think of them as global pointers - since you're creating two different ones, they point to different things. And the state should really be failing analysis since you're passing the wrong type into your Drawer's key field...
If you absolutely have to use GlobalKeys for some reason, you would be better off passing the instance created in your outer widget into your Menu class as a member i.e. this.scaffoldKey, but this isn't recommended.
Using Scaffold.of, this is what your code would look like in the onTap function:
onTap: () {
// On tap this, I want to show a snackbar.
Scaffold.of(context).showSnackBar(showSnack('Error. Could not log out'));
},
You can achieve this functionality by using builder widget you don't need to make separate GlobalKey or pass key as a parameter. Just wrap a widget to Builder widget
class CustomDrawer extends StatelessWidget {#override Widget build(BuildContext context) {
return new Drawer(
child: new ListView(
children: <Widget>[
new Builder(builder: (BuildContext innerContext) {
return ListTile(
dense: true,
title: new Text('My Text'),
onTap: () {
Navigator.of(context).pop();
Scaffold.of(innerContext).showSnackBar(SnackBar(
content: Text('Added added into cart'),
duration: Duration(seconds: 2),
action: SnackBarAction(label: 'UNDO', onPressed: () {}),
));
}
);
})
],
),
);}}
From your first question
In other to reference the parent scaffold in the menu widget you can pass the _scaffoldkey to the menu widget as parameter and use ScaffoldMessenger.of() to show snackbar as shown below
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// Root Widget
#override
Widget build(BuildContext context) {
return MaterialApp(
// App name
title: 'Flutter SnackBar',
// Theme
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Test(title: 'SnackBar'),
);
}
}
class Test extends StatefulWidget {
final String? title;
final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
Test({#required this.title});
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
key: widget._scaffoldkey,
drawer: Menu(parentScaffoldkey:widget._scaffoldkey),
appBar: AppBar(
title: Container(
child: Text('Dashboard'),
),
bottom: TabBar(
tabs: <Widget>[
Tab(text:"Home"),
Tab(text:"About")
],
),
),
body: TabBarView(
children: <Widget>[
Text("Home"),
Text("About")
],
),
),
);
}
}
Menu part as shown
class Menu extends StatelessWidget {
final parentScaffoldkey;
Menu({this.parentScaffoldkey});
#override
Widget build(BuildContext context) {
return new Drawer(
child: new ListView(
children: <Widget>[
new ListTile(
dense: true,
title: new Text('My Text'),
onTap: () {
// On tap show a snackbar.
// ScaffoldMessenger will call the nearest Scaffold to show snackbar
ScaffoldMessenger.of(this.parentScaffoldkey.currentContext).showSnackBar(SnackBar(content:Text('Error. Could not log out')));
},
),
],
),
);
}
}
Also,you have to call snackbar via Scaffold because it provides the SnackBar API and manages it

Resources