what is the best way to use MaterialPageRoute in list view - flutter

I have this ListView and I want to add a MaterialPageRoute. How can I do it that it opens a diverent page when I click on anoter item from the ListView.
(I dont want to want to send selected item data to next screen)
Example:
I click on ExamplePage it shod Navigate to ExamplePage() when I click on TestPage it shod Navigate to TestPage()
Expanded(
child: ListView.builder(
itemCount: categories.length,
itemBuilder: (BuildContext ctx, int index) {
return GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return ExamplePage();
},
),
);
},
child: Container(
margin: const EdgeInsets.all(20),
height: 150,
child: Stack(
children: [
Positioned.fill(
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset(
'images/${categories[index].imgName}.png',
fit: BoxFit.cover),
),
),
Positioned(
bottom: 0,
child: Padding(
padding: const EdgeInsets.all(10.0),
Text(
categories[index].name,
style: const TextStyle(fontSize: 25),
)
),
)
],
),
),
);
},
),
)

Related

How to add Future builder along with card constructor?

I want to add the code below to my existing card constructor but I am unable to do so
child: Container(
height: 50,
width: 100,
child: FutureBuilder<Uri>(
future: createDynamicLink(), //return link
builder: (context, snapshot) {
if (snapshot.hasData) {
Uri? uri = snapshot.data;
return FlatButton(
color: Colors.amber,
onPressed: () => FlutterShare.share(title: 'Example share',
text: 'Example share text',
linkUrl: uri.toString(),
chooserTitle: 'Example Chooser Title'),
child: Text('Share'),
);
}
}),
),
And this is the card widget with which I want to add the future function
child: Container(
margin: const EdgeInsets.only(top: 120.0),
child: GridView(
physics: BouncingScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
children: events.map((title){
return Scaffold(body:
Container(decoration: BoxDecoration(
image:DecorationImage(
image: AssetImage("assets/bg.png"), fit: BoxFit.cover),),
return GestureDetector(
child: Card(
margin: const EdgeInsets.all(14.0),
),
onDoubleTap: () {
Fluttertoast.showToast(msg: "msg");
},
);
}).toList(),
),
I want to be able to use the future function along with the flutterShare functionality when I click on one of the grid card
The event list used above:
List<String> events = [
"Emergency SMS",
"Call",
"Navigation"
];
Truly appreciate any help!

Flutter Visibility with Condition (How can I hide only one widget with condition)

I have a problem with using Visibility widget.
What I want to do is hiding certain listview's by depending user's click on my Row. But when User click on row, all Listview is showing. When clicked again, all listview widget's are going away.
What I want to do is with images:
This is how my page looks
This is what happens when I click on arrow button or "Sezon 1" Text
This is what I want to do when I click on arrow button or "Sezon 1" Text
What I'm trying to do is When I click Season 2, it will show season 2 episodes. When I click season 3 it will show season 3 episodes etc.
Here is my code (I know It's a little messy for right now, apologize for that) :
GestureDetector is working same for every click.
bool viewVisible = false;
void hideWidget() {
setState(() {
viewVisible = !viewVisible;
print(viewVisible);
});
StreamBuilder<QuerySnapshot>(
stream: seasons.snapshots(),
builder:
(BuildContext context, AsyncSnapshot asyncSnapshot) {
if (asyncSnapshot.hasError) {
return Center(
child:
Text('Error'));
} else {
if (asyncSnapshot.hasData) {
List<DocumentSnapshot> listOfDocumentSnap =
asyncSnapshot.data.docs;
return Padding(
padding: const EdgeInsets.only(top: 0, left: 0),
child: Align(
alignment: Alignment.topLeft,
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: listOfDocumentSnap.length,
itemBuilder: (context, index) {
var episodes = firestore
.collection('shows')
.doc(data.id)
.collection('Seasons')
.doc(listOfDocumentSnap[index].id)
.collection('Episodes');
return Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(
top: 0, left: 18, right: 18),
child: GestureDetector(
onTap: () {
hideWidget();
},
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
8),
border: Border.all(
color: Colors.pink)),
child: Row(
children: [
SizedBox(
width: 20,
),
Text(
listOfDocumentSnap[index]
.get('name')
.toString()
.toUpperCase(),
style: TextStyle(
fontSize: 20,
color:
Colors.grey[800],
fontWeight:
FontWeight.w700),
),
Spacer(flex: 1),
Icon(
Icons.arrow_drop_down,
size: 45,
color: Colors.pink,
),
],
),
),
),
),
StreamBuilder<QuerySnapshot>(
stream: episodes.snapshots(),
builder: (BuildContext context,
AsyncSnapshot asyncSnapshot) {
if (asyncSnapshot.hasError) {
return Center(
child: Text(
'Error'));
} else {
if (asyncSnapshot.hasData) {
List<DocumentSnapshot>
listOfDocumentSnap =
asyncSnapshot.data.docs;
return Padding(
padding:
const EdgeInsets.only(
top: 5, left: 18.0),
child: Visibility(
visible: viewVisible,
child: Align(
alignment:
Alignment.topLeft,
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount:
listOfDocumentSnap
.length,
itemBuilder:
(context,
index) {
return ListTile(
onTap: () {
setState(
() {
selectedIndex =
index;
});
},
trailing:
Icon(Icons
.play_arrow),
title: Text(listOfDocumentSnap[
index]
.id
.toString()),
);
/* return Text(
listOfDocumentSnap[
index]
.get(
'name'));*/
},
),
],
),
),
),
);
} else {
return Center(
child:
CircularProgressIndicator());
}
}
},
),
SizedBox(
height: 30,
)
],
);
},
),
],
),
),
);
} else {
return Center(child: CircularProgressIndicator());
}
}
},
),
Sorry, I did not check what is wrong with your code. But, instead of writing your own hide/show logic for each row, try to use Flutter's ExpansionTile widget. It will handle the expanded/collapsed states for you:
https://medium.com/flutterdevs/expansion-tile-in-flutter-d2b7ba4a1f4b
There are two different way I know to handle widget visibility. Create a bool to switch visibility. I'm using _show.
Using if condition
inside (column or any widget)
if (_show) Container(),
Using Visibility Widget
Column(
children: [
Visibility(
visible: _show,
child: Container(),
),
)

How to Navigate to next page without clearing current page data

I am facing a problem with displaying image in the grid view in Flutter.
1) I am fetching 25 images from Firestore but these images are not loaded from top to bottom. these images are loaded asynchronously. I want to load all the images one by one from top to bottom so, the other images which are not on the screen should be loaded when they are scrolled.
2) When I tap any of the Image it is taken to FullScreen Page. I have used navigator. push to navigate from one page to another. But, when I again tap back button in FullScreen Page, all the Images get loaded from the beginning. I want all the images not to be loaded again.
This is the code Where Images are loaded.
class CategoryGrid extends StatefulWidget {
#override
_CategoryGridState createState() =>
_CategoryGridState();
}
class _CategoryGridState extends State<CategoryGrid> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: StreamBuilder(
stream: Firestore.instance.collection(label).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(Colors.black54),
),
),
);
} else {
return SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Container(
height: 50.0,
margin: EdgeInsets.only(top: 45.0),
child: Text(
displayText,
style: GoogleFonts.poppins(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 25.0,
),
),
),
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 0.6,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
padding: EdgeInsets.all(10.0),
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot imgUrl =
snapshot.data.documents[index];
if (imgUrl == null) {
return CircularProgressIndicator();
} else {
return GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return FullScreenPage(
image: "${imgUrl['image']}");
}));
},
child: Container(
child: ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(5.0)),
child: FadeInImage(
image: NetworkImage(
"${imgUrl['image']}",
),
fit: BoxFit.fill,
placeholder: AssetImage(
'images/Loadinghorizontal.jpg'),
),
),
),
);
}
},
),
],
),
),
);
}
},
),
);
}
}
This is the code which is pushed to another screen while tapped
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black54,
body: SafeArea(
child: Stack(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Image.network(
image,
fit: BoxFit.cover,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(),
);
},
),
),
Positioned(
top: 12.0,
left: 12.0,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
),
),
),
],
),
),
);
Use the cached_network_image package, it is perfect because it allows you to put the images you have downloaded in the cache memory of the phone, so here is how you are going to do it :
- You will update your pubspec.yaml file
By adding this in the dependencies cached_network_image: ^2.2.0+1
You do flutter pub get and voila
- Small Example
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/200x150",
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
colorFilter:
ColorFilter.mode(Colors.red, BlendMode.colorBurn)),
),
),
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),

Flutter sort data Firestore with Streambuilder

My goal: When the user presses the "List" button inside "_mainListItem" I want the listview to get sorted by orderBy. Aswell as updated on screen
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class mainlist extends StatefulWidget {
#override
_mainlistpage createState() => _mainlistpage();
}
class _mainlistpage extends State<mainlist> {
Widget homePage() {
return StreamBuilder(
stream: Firestore.instance.collection("Test").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text("Loading");
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_mainListItem(context, snapshot.data.documents[index]));
},
);
}
Widget _mainListItem(BuildContext context, DocumentSnapshot document) {
return Card(
color: Colors.white,
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => profile(context, document)));
},
child: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12))),
child: Row(
children: [
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
children: <Widget>[
Stack(
alignment: Alignment.topRight,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 5),
child: ClipRRect(
borderRadius:
BorderRadius.circular(0.0),
child: FittedBox(
child: Image.asset(
"assets/Profile Picture.png",
fit: BoxFit.fill,
)),
),
),
Padding(
padding: const EdgeInsets.only(
top: 7, right: 4),
child: Text(
'Test',
style: TextStyle(fontSize: 12),
),
),
]),
Row()
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
document['name'],
),
// Text("2km"),
],
),
],
),
],
),
),
],
),
),
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 5, bottom: 5),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 10, right: 7),
child: Container(
child: Material(
borderRadius: BorderRadius.circular(5),
shadowColor: Colors.black,
elevation: 1,
child: SizedBox(
height: 28,
width: 68,
child: IconButton(
padding: EdgeInsets.only(bottom: 10),
**icon: Icon(Icons.list),
disabledColor: Colors.blue,
iconSize: 25,**
)),
),
),
),
],
),
)
],
)
],
),
),
),
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
backgroundColor: Colors.grey,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.red,
),
title: Text("Test"),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.menu),
iconSize: 30,
color: Colors.white,
)
],
),
body: homePage(),
);
}
}
I have tried
- adding the streambuilder function into the ontapped: on the List button
- have read and watched every video there is and still can't find the solution
note: the app looks weird because I deleted unnecessary information
You can sort the list items before the snapshot method like:
.orderBy('sortField', descending: true).snapshot()
I hope this works for you.
Try mapping the values to a List<CustomObject> and using the list of objects in your list view.
i suggest you use state to determine the field how your list will be sorted by.
this is what i'd do to achieve this (continuing from the same code):
...
class _mainlistpage extends State<mainlist> {
String _orderBy = 'defaultSort'; //? HERE YOU PUT WHAT YOUR SORTING FIELD NAME IS
bool _isDescending = true; //? THIS IS WHAT WILL SET THE ORDER SORTING
Widget homePage() {
return StreamBuilder(
stream: Firestore.instance
.collection("Test")
.orderBy(_orderBy, descending: _isDescending) //? PUT THE ORDERBY QUERY HERE
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text("Loading");
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_mainListItem(context, snapshot.data.documents[index]));
},
);
}
...
somewhere in the class, put the button or dropdown and use setState(...) to set the
states of the new variables.
NOTE: you might have to create 'indexes' in firestore. you will get errors when a new
index is required.

displaying image from firestorage on ListView.builder

I m using firestore for data and firestorage for files and images, so i m using StreamBuilder to load list as per firestore data and i want to download images as per firestore file name, but its not happening
I tried is, created a new method there I did code to get download url , but it is not working
child: StreamBuilder(
stream: Firestore.instance.collection('data').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData)
return Container(
child: Center(child: CircularProgressIndicator()));
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
children: <Widget>[
Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Image.network(
imageLoader(snapshot.data.documents[index].data['flie_ref'].toString()),
fit: BoxFit.fill,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
elevation: 0,
margin: EdgeInsets.all(10),
),
Padding(
padding: EdgeInsets.only(left: 6, right: 6),
child: Card(
elevation: 0,
child: ExpansionTile(
leading: CircleAvatar(
child: Text(snapshot
.data.documents[index].data['amount']
.toString()),
),
title: Text(
snapshot
.data.documents[index].data['desc']
.toString(),
overflow: TextOverflow.ellipsis,
),
children: <Widget>[
Text(snapshot
.data.documents[index].data['desc']
.toString()),
SizedBox(
height: 10,
),
],
),
),
),
],
),
);
});
},
),
Future imageLoader(String string) async {
var url =
await FirebaseStorage.instance.ref().child(string).getDownloadURL();
setState(() {
return url;
});
}
I expect output load respective image but the output is Error: The argument type 'Future' can't be assigned to the parameter type 'Widget'