widget.something in stateful widget - flutter

import 'package:duck/MoreAboutProduct.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class CategoryComponents extends StatelessWidget {
final String NAME;
CategoryComponents(
this.NAME);
#override
Widget build(BuildContext context) {
return Column(
children:[
Text($NAME),
RaisedButton(
child : Text(More Info),
onPressed:(){
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return MoreAboutProduct(
NAMEp: NAME,
}
),
],);
I have this class named CategoryComponents, it has only 1 variable in this example 'NAME', and other classes named Samsung and MoreAboutProduct, I will add the code of others in the following lines, I wanted to call CategoryComponents class in Samsung and pass the value of NAME and other values (not showing other values in this example for simplicity),I wanted to show the value of NAME in Samsung class and their will be a bottom in CategoryComponents class which transfer me to MoreAboutProduct class and show more info about the product but some data has to be for first product only that's why i need connection between Samsung and MoreAboutProduct, I found a way to do it but i really have some issues understanding the code specially the Navigator part and how does a variable in CategoryComponents that is passed in the constructor's parameter in Samsung class can be accessed in MoreAboutProduct class? and the widget.NAME part, I know it's pretty long question but please if you want to down vote it give me an answer first.
import 'package:duck/MoreAboutProduct.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'CategoryComponents.dart';
class Samsung extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
key: _x,
appBar: myAppbar("Samsung"),
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return CategoryComponents(
snapshot.data[index]['NAME']
)};
This is Samsung class, their are other parameters i'm passing but only one of them in this example just making it simple so you understand my quesiton, also that's why i use ListView.builder.
import 'package:duck/myAppbar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'myCarousel.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class MoreAboutProduct extends StatefulWidget {
final String NAMEp;
MoreAboutProduct(
{this.NAMEp});
}
#override
_MoreAboutProductState createState() => _MoreAboutProductState();
}
class _MoreAboutProductState extends State<MoreAboutProduct> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: ...,
body: Column(
children: [
...
),
Expanded(
child: Container(
child: ListView.builder(
itemCount: widget.snapshotLengthp,
itemBuilder: (context, index) {
return Container(
child: Column(
children: [
SpecificationsDetails(context, 'NAME', widget.NAMEp),
....
],
),);},),),),),);
SpecificationsDetails is a Function responsible for the styling, no need to show it.
here are some sample runs :
This image is in Samsung class but Categorycomponents class is responsible for passing data to it and the styling
And this is in MoreAboutProduct class

You can create named routes in your app.
MaterialApp(
// Start the app with the "/" named route. In this case, the app starts
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/more_about_products': (context) => MoreAboutProduct(),
'/samsung': (context) => Samsung(),
},
);
code from flutter docs.
In category components class you can have something like this:
Navigator.of(context).pushNamed("/more_about_products", arguments = {name: this.NAME});
after that you can grab this argument inside the MoreAboutProducts with ModalRoute like this:
class _MoreAboutProductState extends State<MoreAboutProduct> {
#override
Widget build(BuildContext context) {
final args = ModalRoute.of(context).settings.arguments;
// to grab the **name** argument use ***args.name*** like in print function below.
print(args.name)
return Scaffold(
appBar: ...,
body: Column(
children: [
...
),
Expanded(
child: Container(...etc code....
Please read the comment beetween print function and ModalRoute.
for more info view flutter named routes and passing the arguments to named routes

Related

How to Navigate to the different screens after clicking on List Item?

I am getting my data through Hive to ListView, here is my code where I am showing ListView.
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:secret_keeper/Database/Hive/PasswordModel.dart';
import 'package:secret_keeper/screens/home_screen/passwords/ShowData.dart';
class PasswordsNavigation extends StatefulWidget {
#override
_PasswordsNavigationState createState() => _PasswordsNavigationState();
}
class _PasswordsNavigationState extends State<PasswordsNavigation> {
var passwordBox = Hive.box<PasswordModel>('passwordBox');
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: _buildListView(),
)
],
));
}
Widget _buildListView() {
return WatchBoxBuilder(
box: passwordBox,
builder: (context, box) {
Map<dynamic, dynamic> raw = box.toMap();
List list = raw.values.toList();
return ListView.builder(
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (context, index) {
PasswordModel passwordModel = list[index];
return ListTile(
title: Text(passwordModel.websiteName),
subtitle: Text(passwordModel.websiteAddress),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.delete),
onPressed: (){
passwordBox.deleteAt(index);
},
)
],
),
);
},
);
},
);
}
}
I have created a new .dart file named ShowData.dart When I click on any item then how to open this activity? I don't know how to navigate to new screen when i click on list item also i want data like list index n all with navigator.
You should probably create a new widget for the page, like this:
class DetailsPage extends StatelessWidget {
DetailsPage({Key key, required this.id}) : super(key: key);
final int id;
Widget build(BuildContext context) {
// Show details for the item with the given id.
...
}
}
Note that it also takes an id parameter in the constructor.
Then, in the ListTile's onTap method, you can navigate to the new page, passing along the id:
ListTile(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => DetailsPage(id: /* id of the item at the current index */),
));
},
...
),

Managing state in Flutter using Provider

I'm trying to implement Provider state management on counter application to understand Provider's functionality better. I have added two buttons with respect to two different text widget. So, now whenever I click any of the two widget both the Text widgets get update and give same value. I want both the widgets independent to each other.
I have used ScopedModel already and got the desire result but now I want to try with provider.
Image Link : https://i.stack.imgur.com/ma3tR.png
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
print("====Home Page Rebuilt====");
return Scaffold(
appBar: AppBar(
title: Text("HomePage"),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
//crossAxisAlignment:CrossAxisAlignment.center,
children: [
Consumer<CounterModel>(
builder: (context, value, child) {
return CustomWidget(
number: value.count.toString(),
);
},
),
Consumer<CounterModel>(
builder: (context, value, child) {
return CustomWidget(
number: value.count.toString(),
);
},
),
],
)),
);
}
}
class CustomWidget extends StatelessWidget {
final String number;
const CustomWidget({Key key, this.number}) : super(key: key);
#override
Widget build(BuildContext context) {
print("====Number Page Rebuilt====");
return ButtonBar(
alignment: MainAxisAlignment.center,
children: [
Consumer<CounterModel>(
builder: (context, value, child) {
return Text(
value.count.toString(),
style: Theme.of(context).textTheme.headline3,
);
},
),
FlatButton(
color: Colors.blue,
onPressed: () =>
Provider.of<CounterModel>(context, listen: false).increment(),
child: Text("Click"),
),
],
);
}
}
If you want them independent from each other, then you need to differentiate them somehow. I have a bit of a different style to implement the Provider and it hasn't failed me yet. Here is a complete example.
You should adapt your implementation to something like this:
Define your provider class that extends ChangeNotifier in a CounterProvider.dart file
import 'package:flutter/material.dart';
class CounterProvider extends ChangeNotifier {
/// You can either set an initial value here or use a UserProvider object
/// and call the setter to give it an initial value somewhere in your app, like in main.dart
int _counter = 0; // This will set the initial value of the counter to 0
int get counter => _counter;
set counter(int newValue) {
_counter = newValue;
/// MAKE SURE YOU NOTIFY LISTENERS IN YOUR SETTER
notifyListeners();
}
}
Wrap your app with a Provider Widget like so
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
/// don't forget to import it here too
import 'package:app/CounterProvider.dart';
void main() {
runApp(
MaterialApp(
initialRoute: '/root',
routes: {
'/root': (context) => MyApp(),
},
title: "Your App Title",
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
/// Makes data available to everything below it in the Widget tree
/// Basically the entire app.
ChangeNotifierProvider<CounterProvider>.value(value: CounterProvider()),
],
child: MaterialApp(
home: HomeScreen(),
),
);
}
}
Access and update data anywhere in the app
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
/// MAKE SURE TO IMPORT THE CounterProvider.dart file
import 'package:app/CounterProvider.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
CounterProvider counterProvider;
#override
Widget build(BuildContext context) {
/// LISTEN TO THE CHANGES / UPDATES IN THE PROVIDER
counterProvider = Provider.of<CounterProvider>(context);
return Scaffold(
appBar: AppBar(
title: Text("HomePage"),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
//crossAxisAlignment:CrossAxisAlignment.center,
children: [
_showCounterButton(1),
_showCounterButton(2),
],
),
),
);
}
Widget _showCounterButton(int i) {
return ButtonBar(
alignment: MainAxisAlignment.center,
children: [
Text(
i == 1
? counterProvider.counter1.toString()
: counterProvider.counter2.toString(),
style: Theme.of(context).textTheme.headline3,
),
FlatButton(
color: Colors.blue,
onPressed: () {
/// UPDATE DATA IN THE PROVIDER. BECAUSE YOU're USING THE SETTER HERE,
/// THE LISTENERS WILL BE NOTIFIED AND UPDATE ACCORDINGLY
/// you can do this in any other file anywhere in the Widget tree, as long as
/// it it beneath the main.dart file where you defined the MultiProvider
i == 1
? counterProvider.counter1 += 1
: counterProvider.counter2 += 1;
setState(() {});
},
child: Text("Click"),
),
],
);
}
}
If you want, you can change the implementation a bit. If you have multiple counters, for multiple widgets, then just create more variables in the CounterProvider.dart file with separate setters and getters for each counter. Then, to display/update them properly, just use a switch case inside the _showCounterButton() method and inside the onPressed: (){ switch case here, before setState((){}); }.
Hope this helps and gives you a better understanding of how Provider works.

Get updated State outside a Widget tree with Redux

Is it possible to get an up-to-date state from the Store outside the Widget tree?
In Provider, you can easily do that by calling Provider like this and the state will update if there is any change.
Provider.of<WelcomeBloc>(context)
But when I call:
StoreProvider.of<AppState>(context).state.currentPage;
I just get the current state but it doesn't update on changes (or I am doing something wrong there)
In that case, I need to use that call in a block which updates on changes... what in my example is not a case
example
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:ui_flutter/model/app_state.dart';
import './footer.dart';
import './viewWrapper.dart';
import './header.dart';
class Welcome extends StatefulWidget {
#override
_WelcomeState createState() => _WelcomeState();
}
class _WelcomeState extends State<Welcome> {
#override
Widget build(BuildContext context) {
int currentPage = StoreProvider.of<AppState>(context).state.currentPage; // This build method is invoked once only so I don't have update data
print('current page: $currentPage');
return Scaffold(
body: StoreConnector<AppState, AppState>(
converter: (store) => store.state,
builder: (context, state) {
return SafeArea(
child: Stack(
children: <Widget>[
ViewerWrapper(),
Footer(
currentStep: state.currentPage,
totalSteps: 3,
activeColor: Colors.grey[800],
inactiveColor: Colors.grey[100],
),
WelcomeHeader,
],
),
);
},
),
);
}
}
Thanks in advance!

Circular Progress Indicator not displayed when the condition is true

import 'package:flutter/material.dart';
import 'package:futureprovider/Employee.dart';
import 'package:futureprovider/EmployeeService.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp(
));
class MyApp extends StatelessWidget {
final PostService fur = PostService();
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
FutureProvider(create:(context)=> fur.getEmployees(),
catchError: (context,e){
print(e.toString());
},
//initialData: [Post(id:1,name: 1,title: '1',body: '1')],
)
],
child: MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Posts Dashboard")),
body:TilesOfPost(),
),
),
);
}
}
class TilesOfPost extends StatelessWidget {
#override
Widget build(BuildContext context) {
List<Post> posts = Provider.of<List<Post>>(context);
print("Length:"+posts.length.toString());
return (posts==null)? Center(child:CircularProgressIndicator()):ListView.builder(
itemCount: posts.length,
itemBuilder: (context,index){
return ListTile(
title: Text(posts[index].id.toString()),
subtitle: Text(posts[index].name.toString())
);
}
);
}
}
In the following code,
I have Future Provider which provides some future values and when i execute the code,
initially when the List is null it should show Circular Progress Widget,
but it gives an exception for the ListView being build with length null.
How do i show Circular Progress Inidcator when the Future value is still not received
Your print statement is the actual problem. when data is null then also it check for length, so i throws error because of that you are also not able to see CircularProgressIndicator().

flutter firestore push document data to details screen

I need to click on the list, and open a new detail page. I've looked everywhere for examples of how to do this and I found many. However my data is structured different and even though my code has no errors it will not populate the details page. Here is what i'm working with:
//page 1
child: ListView.builder(
itemCount:
_documents == null ? 0 : _documents.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
"assets/images/roomfield1.png"),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter),
color:
Theme.of(context).canvasColor,
),
child: ListTile(
title: Text(_documents[index]
['title']),
subtitle: Text(_documents[index]
["description"]),
trailing: Text(_documents[index]
['citystate']),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DetailPage(_documents[index])));
})));
},
Here is the details page:
// details page
import 'package:flutter/material.dart';
class DetailPage extends StatefulWidget {
DetailPage(_documents, {Key key,}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
var _documents;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Details Page'),
),
body: ListView.builder(
itemCount: _documents == null ? 0 : _documents.length,
itemBuilder: (BuildContext context,[index]) {
return ListTile(
title: Text(_documents[index]['title']),
);
}));}}
My documents use the documentId. i tried passing the id and then using it in a stream builder and that didn't work either. I think my code is close, but I don't know what is wrong. Also I cant change the structure of the data, because it is used all over the place in this format. I'm guessing its something simple that i missed, maybe the constructor on the details page but i'm not sure...Any insight is appreciated.
You created a variable called _documents at the top of the class. However, to retrieve the value of the actual _documents variable in the DetailPage class, you need to use widget.documents. I have provided the correct code below for you to use.
Also, I don't know why you're using a StatefulWidget for your DetailPage class since you don't seem to be doing anything that requires state management. You could easily make this a StatelessWidget but maybe there's more code that I'm unable to see.
// details page
import 'package:flutter/material.dart';
class DetailPage extends StatefulWidget {
final var documents; // created new final variable that will be initialized by the constructor
DetailPage(this.documents);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
//var _documents; // Don't use this
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Details Page'),
),
body: ListView.builder(
itemCount: widget.documents == null ? 0 : widget.documents.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(widget.documents[index]['title']), // don't know why you need to specify the index since you already did in your other classs
);
}));}}