hello I am new in flutter and bloc, I imagine that I have 2 screens (login and home screen). In login screen I am using bloc that post data and I want to call that data in my home screen. Can someone give me example to do that?
There are many ways to do that, I can name a few.
You navigate to the new Widget (the screen) and pass to that Widget constructor the data you want it to have.
You can use Provider to provide that data and wrap the new screen on it, then navigate to the new screen.
If this is some data that should be accessed across the app, you could provide the entire BLoC to the entire App and get the BLoC's reference on this new screen and then get the data directly from the BLoC.
If you just want to pass a value to home page from login page, you can do like this:
class Home extends StatelessWidget {
final String username;
Home(this.username);
#override
Widget build(BuildContext context) {
return Container();
}
}
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (ctx) {
return Home('flutter');
}));
}),
);
}
}
Related
I have a problem using Flutter Provider...
After Onbording screens I click to Next Button and needs to show me Welcome Screen (where i choose to log in with phone number)
But after clicking to Next Button i get this error - Could not find the correct Provider above this WelcomeScreen Widget
class _WelcomeScreenState extends State<WelcomeScreen> {
#override
Widget build(BuildContext context) {
final ap = Provider.of<AuthProvider>(context, listen: true);
return Scaffold(
body: SafeArea(
child: Center(
Make sure your Provider<> widget is present and at the root(like parent of MaterialApp for instance) to make sure it is in widget tree across rebuilds.
As far as I can see your code, you're calling Provider watch in welcome screen which prolly doesn't have the Provider in its tree. Move the watch to OnboardingScreen.
I'm trying to make a card clickable and navigate to another page 'forecastWeather.dart'. But I can't seem to figure out how I can fix the error I'm getting. The error message says
Another exception was thrown: Navigator operation requested with a context that does not include a Navigator.
I'm using a TabBarView with two tabs and one contains a card which should be clickable and navigate to another page 'forecastWeather.dart'. Please help!
In order to get use navigator.push, you must pass the context of your widget and have a MaterialApp somewhere in your tree, you do both, so the code should work, but it doesn't.
The reason is simple, the context you are passing is outdated, you are first creating the context when the build method begins, at that point, there is no material app, then you add a material app, but the context already exists, so the context you are passing when calling Navigator.push(context ... has no MaterialApp.
A possible fix is to use the Builder widget to make a new context after you create the MaterialApp widget:
#override
Widget build(BuildContext context) {
// context has no material app.
return MaterialApp(
home: Builder(
builder: (context) {
// this context does have a material app and is safe to use.
return DefaultTabController( ... );
}
),
);
}
Another fix is to move the code into a new widget with it's own context:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainPage(),
);
}
}
class MainPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
// this context was created after the material app.
return DefaultTabController(...);
}
}
i suggest you to use get: ^4.6.1 package.
with this package you just need to use this for any navigation:
Get.to(ForecastWeather());
this package have so other features read its document here
[1]: https://pub.dev/packages/get
I am coming from android.
In android ,if i want to bypass an activity i will call intent method in onCreate something like this.
onCreate(){
if(condition satisfied){
Intent myIntent = new Intent(CurrentActivity.this, NextActivity.class);
CurrentActivity.this.startActivity(myIntent);
}
}
But i cant understand how to write this code in flutter and navigate another screen .
And I also don't know that this code will write in initState() or build().
note: In this case in If condition, I used StreamBuilder,
I need in following steps,
At screen start
Blank screen
if Condition will be true than return Container();
else leave this Screen(Activity) go to another screen.
Use this :
return isSomethingtrue ? HomeScreen() : OtherScreen(),
Then - In your HomeScreen() Build a Container()
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container();
}
}
I have a task that will run in the background (in an isolate) and when it finishes, I want to show a Snackbar. However, the user may navigate to a different screen from the one where the task was initiated. How do I show an 'app-level' Snackbar, not bound to any particular screen?
Edit: I found this: How to show a SnackBar from async executions when no context is available?, has some good information and option 1 (Display errors in page scaffolds) seems to be what I want, but I need to implement all by myself. I was hoping for something built in into Flutter.
I'd give this a try where you go for an abstract base class where you implement the 'listener', which then all your pages extend from instead of e.g. StatelessWidget.
Instead of overriding the normal build method, just override your new special build.
Pseudo code (here with BlocListener):
abstract class MySnackbarShowingPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocListener<SubjectBloc, SubjectState>(
listener: (context, state) {
// TODO: implement snackbar display
},
child: mySpecialBuild(context),
);
}
Widget mySpecialBuild(BuildContext context);
}
class MySpecificPage extends MySnackbarShowingPage {
#override
Widget mySpecialBuild(BuildContext context) {
// TODO: implement mySpecialBuild as your normal page does today
}
}
I am working on an app in Flutter and I'm pretty new to it/Dart. I already created the login, signup etc and everything works perfectly fine. Now I want to create a "Login-Wall" Template for every View that needs the user to be logged in. If the user is not logged in, he should be returned to the LoginView, if the api-call is still loading, it should not show anything but a loading screen called LoadingView(). I started by creating a Stateful Widget called AuthorizedLayout:
class AuthorizedLayout extends StatefulWidget {
final Widget view;
AuthorizedLayout({this.view});
_AuthorizedLayoutState createState() => new _AuthorizedLayoutState();
}
The state utilizes a Future Builder as follows:
Widget build(BuildContext context) {
return FutureBuilder<User>(
future: futureToken,
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return NoConnectionView();
case ConnectionState.active:
case ConnectionState.waiting:
return LoadingView();
case ConnectionState.done:
if(snapshot.data != null) {
print("User Data loaded");
return widget.view;
} else
return LoginView();
}
},
);
}
As you can see, it should load the userdata, and when it's finished it should return the view. The futureToken represents the Future that will return the User-Object from the server after an api-request. In any other case it should show the Loading/Error/Login Page.
I'm calling it like this:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: AuthorizedLayout(
view: DashboardView(),
),
);
}
In the Build method of the Dashboard view I have a "print('Dashboard View');". The problem I have is that in the output the 'Dashboard View' is printed before the 'User Data Loaded'. That means I can't access the loaded user data in that view. This means that this solution does not work the way I intended it to.
Now for my question: Is there any way I can build this "Login-Wall" and pass the user data to every view that is inside the login wall? I hope the code I posted explains the idea I'm trying to go for.
Is there any way I can build this "Login-Wall" and pass the user data to every view that is inside the login wall?
Absolutely! At a basic level, you're talking about state management. Once a user logs into your app, you want to store that user data so that it's accessible to any widget within the widget tree.
State management in Flutter is a hotly-debated topic and while there are a ton of options, there is no defacto state management technique that fits every app. That said, I'd start simple. One of the simplest and most popular options is the scoped_model package.
You can read all of the details here, but the gist is that it provides utilities to pass a data model from a parent widget to its descendants.
First, install the package.
Second, you'll want to create a model that can hold the user data that you want to be accessible to any widget in the tree. Here's a trivial example of what that might look like:
// user_model.dart
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
class UserModel extends Model {
dynamic _userData;
void setUserData(dynamic userData) {
_userData = userData;
}
String getFirstName() {
return _userData['firstName'];
}
static UserModel of(BuildContext context) =>
ScopedModel.of<UserModel>(context);
}
Next, we'll need to make an instance of this UserModel available to all widgets. A contrived way of doing this would be to wrap your entire app in a ScopedModel. Example below:
// main.dart
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'login_view.dart';
import 'user_model.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScopedModel<UserModel>(
model: UserModel(),
child: MaterialApp(
theme: ThemeData.light(),
home: LoginView(),
),
);
}
}
In the above code, we're wrapping our entire instance of MaterialApp in a ScopedModel<UserModel>, which will give every widget in the application access to the User model.
In your login code, you could then do something like the following when your login button is pressed:
onPressed() async {
// authenticate your user...
var userData = await someApiCall();
// set the user data in our model
UserModel.of(context).setUserData(userData);
// go to the dashboard
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DashboardView(),
),
);
}
Last but not least, you can then access that user data through the UserModel like so:
// dashboard_view.dart
import 'package:flutter/material.dart';
import 'package:scoped_model_example/user_model.dart';
class DashboardView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(
UserModel.of(context).getFirstName(),
),
),
],
);
}
}
Check out the docs on scoped_model for more details. If you need something more advanced, there are a number of other state management patterns in Flutter such as BloC, Redux, Mobx, Provider and more.
So I just got what was happening. I was passing the already-built widget to the AuthorizedView. What I actually had to pass was a Builder instead of a Widget.
class AuthorizedLayout extends StatefulWidget {
final Builder viewBuilder;
AuthorizedLayout({this.viewBuilder});
_AuthorizedLayoutState createState() => new _AuthorizedLayoutState();
}
Calling it like this:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: AuthorizedLayout(
viewBuilder: Builder(builder: (context) => DashboardLayout()),
),
);
}
Note that I recalled the final variable to viewBuilder instead of view, compared to the example above.
This will actually build the widget AFTER the userdata is loaded.