I used a grid view list in order to show some items in another list that contain images
and doesn't show the items, instead it shows the loading icon
this is my code:
import 'package:flutter/material.dart';
import 'package:sct/list/list.dart';
class badriya2 extends StatefulWidget {
#override
State<badriya2> createState() => _badriya2State();
}
class _badriya2State extends State<badriya2> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"She codes",
),
),
body: FutureBuilder(builder: (context, AsyncSnapshot snapshot) {
height:
MediaQuery.of(context).size.height;
width:
MediaQuery.of(context).size.width;
if (snapshot.hasData) {
List resList = snapshot.data;
child:
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: resList.length,
itemBuilder: (context, index) {
primary:
true;
padding:
const EdgeInsets.all(20);
shrinkWrap:
true;
children:
<Widget>[
Card(
child: Center(
child: CircleAvatar(
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset(
list[0].image,
),
),
minRadius: 50,
maxRadius: 75,
),
),
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
];
return Center(child: CircularProgressIndicator());
}));
}
return Center(child: CircularProgressIndicator());
}));
}
}
and this is the list :
import 'package:flutter/cupertino.dart';
List list = [
{
Image.asset('assets/images/butterfly.jpg'),
},
{
Image.asset('assets/images/flower.jpg'),
},
{
Image.asset('assets/images/glass.jpg'),
},
{
Image.asset('assets/images/sun.jpg'),
},
{
Image.asset('assets/images/lighting.jpg'),
},
{
Image.asset('assets/images/phone.jpg'),
},
{
Image.asset('assets/images/eye.jpg'),
},
{
Image.asset('assets/images/photo1.jpg'),
},
];
the point of this code is not to duplicate the items in grid view, I want to write in one line
Add future method onfuture inside FutureBuilder.
return FutureBuilder(
future: yourFutureMethod(),
builder: (context, snapshot) {...},
);
You use the Future Builder but you didn't mention any future. Set the Future
import 'package:flutter/material.dart';
import 'package:sct/list/list.dart';
class badriya2 extends StatefulWidget {
#override
State<badriya2> createState() => _badriya2State();
}
class _badriya2State extends State<badriya2> {
var dummy;
#override
void initState() {
super.initState();
dummy = _getimages();
print("data ${dummy}");
}
_getimages() async {
var imagelist = await list;
print(imagelist);
return imagelist;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"She codes",
),
),
body: FutureBuilder(
future: _getimages(),
builder: (context, AsyncSnapshot snapshot) {
if(snapshot.hasError) print(snapshot.error);
return snapshot.hasData
?GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
List reslist = snapshot.data;
return Column(
children: [
Card(
child: Center(
child: Container(
width: 100,
height: 100,
child: CircleAvatar(
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.network(reslist[index].toString(),)
),
minRadius: 50,
maxRadius: 75,
),
),
),
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
],
);
}
):
Center(
child:CircularProgressIndicator()
);
}
)
);
}
}
And please assign proper list of data
import 'package:flutter/cupertino.dart';
List list= [
"https://dlanzer.com/flutter_api/assets/uploads/images/farm_2021-10-25%2005:09:48am.png",
"https://dlanzer.com/flutter_api/assets/uploads/images/farm_2021-10-25%2005:09:11am.png",
"https://dlanzer.com/flutter_api/assets/uploads/images/farm_2021-10-19%2002:51:18pm.png",
"https://dlanzer.com/flutter_api/assets/uploads/images/farm_2021_10_12_04_30_13_pm.png",
];
Here I use network images You change to asset images
Related
I have the code below which feed a list with 10 results from firebase. In this case it shows only the 10 items, now I wanna, when user gets the bottom of results, it loads more 10 items and add it to the list. I already have the scrollController and it works.. I receive the log "LOAD HERE" when I get the bottom of the results.
My doubt is how to add the new 10 items in the list?
scrollListener() async {
if (scrollController.position.maxScrollExtent == scrollController.offset) {
print('LOAD HERE');
}
}
#override
void initState() {
scrollController.addListener(scrollListener);
super.initState();
}
#override
void dispose() {
scrollController.removeListener(scrollListener);
super.dispose();
}
loadList(submenu ,callback, context, deviceSize){
return FutureBuilder(
future: ctrlLab.loadList(submenu, 10),
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.error != null) {
print(snapshot.error);
return Center(child: Text('ERROR!'));
}else {
return GridView.builder(
padding: EdgeInsets.all(10.0),
controller: scrollController,
itemCount: snapshot.data.length,
itemBuilder: (ctx, i) {
Item item = snapshot.data[i];
if (i < snapshot.data.length) {
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
background: Container(
padding: EdgeInsets.all(10.0),
color: Colors.grey[800],
child: Align(
alignment: AlignmentDirectional.centerEnd,
child: Icon(
Icons.delete,
color: Colors.white,
size: 40,
),
),
),
onDismissed: (DismissDirection direction) {
ctrl.onDismissed(callback, item);
},
child: GestureDetector(
child: Card(
elevation: 5.0,
child: Padding(
padding: EdgeInsets.all(10.0),
child: GridTile(
child: Hero(
tag: "${item}",
child: item.imageUrl == null
? setIconLab(item)
: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: setIconLab(item),
placeholder: (ctx, url) =>
Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Image.asset('assets/images/noPhoto.jpg',
fit: BoxFit.cover),
),
),
footer: Container(
padding: EdgeInsets.all(8.0),
color: Colors.white70,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.name
),
),
],
),
),
),
),
),
),
);
}
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCountAndLoading(
itemCount: snapshot.data.length + 1,
crossAxisCount: deviceSize.width < 600 ? 2 : 3,
childAspectRatio: 0.7,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
),
);
}
},
);
}
Infinite Scrolling in ListView
I have achieved this case by using the local field instead of getting data from firebase. Hope it will give you some idea.
import 'package:flutter/material.dart';
class ListViewDemo extends StatefulWidget {
ListViewDemo({Key key}) : super(key: key);
#override
_ListViewDemoState createState() => _ListViewDemoState();
}
class _ListViewDemoState extends State<ListViewDemo> {
ScrollController controller;
int count = 15;
#override
void initState() {
super.initState();
controller = ScrollController()..addListener(handleScrolling);
}
void handleScrolling() {
if (controller.offset >= controller.position.maxScrollExtent) {
setState(() {
count += 10;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List view'),
),
body: ListView.builder(
controller: controller,
itemCount: count,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Item $index'),
);
},
),
);
}
#override
void dispose() {
controller.removeListener(handleScrolling);
super.dispose();
}
}
You have to add another 10 data to the crtLap.loadList(subMenu, 20) and call setState inside the scrollListener to rebuild the widget about the changes.
var data = crtLap.loadList(subMenu, 10);
scrollListener() async {
if (scrollController.position.maxScrollExtent == scrollController.offset) {
setState((){
data = crtLap.loadList(subMenu, 20);
});
}
}
and use this data field to the FutureBuilder directly,
loadList(submenu ,callback, context, deviceSize){
return FutureBuilder(
future: data,
builder: (ctx, snapshot) {
.....
...
..
}
I made a grid view in the flutter app. But like the Pictures on the below link , I want to create an icon on the picture and change the background color After tap the picture,
I've been looking for ways, but I've finally got a question. I'd appreciate it from the bottom of my heart if you'd let me know.
Please enter img link(below)
https://firebasestorage.googleapis.com/v0/b/instaclone-2-fd9de.appspot.com/o/post%2F12344.png?alt=media&token=89d46c03-83ba-4d30-b716-e9b718c1340b
Widget _bodyBuilder() {
// TODO : 그 예시를 어떻해 stream View로 보여줄것인가
return StreamBuilder <QuerySnapshot>(
stream: _commentStream(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if(!snapshot.hasData){
return Center(child: CircularProgressIndicator());
}
var items = snapshot.data?.documents ??[];
var fF = items.where((doc)=> doc['style'] == "오피스룩").toList();
var sF = items.where((doc)=> doc['style'] == "로맨틱").toList();
var tF = items.where((doc)=> doc['style'] == "캐주").toList();
fF.addAll(sF);
fF.addAll(tF);
fF.shuffle();
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 0.6,
mainAxisSpacing: 2.0,
crossAxisSpacing: 2.0),
itemCount: fF.length,
itemBuilder: (BuildContext context, int index) {
return _buildListItem(context, fF[index]);
});
},
);
}
Widget _buildListItem(context, document) {
return Ink.image(
image : NetworkImage(document['thumbnail_img']),
fit : BoxFit.cover,
child: new InkWell(
//I think we need to get something in here....
onTap: (){},
),
);
}
You should create List of Image which have isSelected value and when the user clicks on item them set true/false base of the old value which have imageURL and isSelected variable. First, you should store value in List Of Image obj. which coming from Firebase/API then flow below step. I have created a demo and post here. Please take reference.
Example code
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
List<ImageData> imageList;
#override
void initState() {
super.initState();
imageList = ImageData.getImage();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 0.5,
crossAxisCount: 5,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0),
itemCount: imageList.length,
itemBuilder: (builder, index) {
return InkWell(
onTap: () {
setState(() {
imageList[index].isSelected = !imageList[index].isSelected;
});
},
child: Stack(
children: [
_getImage(imageList[index].imageURL),
Opacity(
opacity: imageList[index].isSelected ? 1 : 0,
child: Stack(
children: [
Container(
width: double.infinity,
height: double.infinity,
color: Colors.black38,
),
Center(
child: CircleAvatar(
backgroundColor: Colors.greenAccent,
child: Icon(
Icons.check,
color: Colors.white,
),
),
)
],
),
)
],
));
},
),
);
}
_getImage(url) => Image.network(
url,
height: 500,
fit: BoxFit.fitHeight,
);
#override
void dispose() {
super.dispose();
}
}
class ImageData {
String imageURL;
bool isSelected;
int id;
ImageData(this.imageURL, this.isSelected, this.id);
static List<ImageData> getImage() {
return [
ImageData('https://picsum.photos/200', false, 1),
ImageData('https://picsum.photos/100', false, 2),
ImageData('https://picsum.photos/300', false, 3),
ImageData('https://picsum.photos/400', false, 4),
ImageData('https://picsum.photos/500', false, 5),
ImageData('https://picsum.photos/600', false, 6),
ImageData('https://picsum.photos/700', false, 7),
ImageData('https://picsum.photos/800', false, 8),
ImageData('https://picsum.photos/900', false, 9),
];
}
}
Output
I display many images in a Staggered Gridview in a Flutter application.
Everytime I call setState({}), for example after deleting an item, the page jumps to top. How could I remove this behavior?
This is my code:
final _scaffoldKey = new GlobalKey<ScaffoldState>();
.. outside the build function. And then...
return loadingScreen == true
? LoadingScreen()
: Scaffold(
key: _scaffoldKey,
body: CustomScrollView(
slivers: <Widget>[
_AppBar(
theme: theme,
index: index,
albumImagePath: albumImagePath,
albumID: albumID,
albumValue: albumValue,
addPictureToGallery: _addPictureToGallery,
),
SliverToBoxAdapter(
child: Column(
children: <Widget>[
InfoBar(
albumPicturesSum: albumPicturesSum,
getBilderString: _getBilderString,
theme: theme,
getVideoProgress: _getVideoProgress,
progress: progress,
),
albumID == 99999999
? // Demo Projekt
DemoImageGrid(
demoImageList: demoImageList,
getDemoImagesJson: _getDemoImagesJson,
)
: UserImageGrid(
picturesData: picturesData,
albumID: albumID,
showPictureActions: _showPictureActions)
],
),
)
],
),
);
}
The UserImageGrid looks like the following:
class UserImageGrid extends StatelessWidget {
final Pictures picturesData;
final int albumID;
final Function showPictureActions;
final _key = new UniqueKey();
UserImageGrid(
{#required this.picturesData,
#required this.albumID,
#required this.showPictureActions});
#override
Widget build(BuildContext context) {
return FutureBuilder(
key: _key,
future: picturesData.getPicturesFromAlbum(albumID),
builder: (BuildContext context, AsyncSnapshot snapshot) {
// Normale Projekte
if (snapshot.hasData && snapshot.data.length == 0) {
return Center(
child: Column(
children: <Widget>[
Lottie.asset('assets/lottie/drone.json',
width: 250,
options: LottieOptions(enableMergePaths: false)),
],
),
);
}
if (!snapshot.hasData ||
snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Container(
child: StaggeredGridView.countBuilder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.all(0),
crossAxisCount: 6,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) =>
GestureDetector(
onLongPress: () {
showPictureActions(snapshot.data[index]);
},
onTap: () async {
await showDialog(
context: context,
builder: (_) {
return Dialog(
child: Stack(
children: [
Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0,
),
height: 500.0,
child: ClipRect(
child: PhotoView(
maxScale:
PhotoViewComputedScale.covered * 2.0,
minScale:
PhotoViewComputedScale.contained *
0.8,
initialScale:
PhotoViewComputedScale.covered,
imageProvider: FileImage(
File(snapshot.data[index].path))),
),
),
Positioned(
bottom: 20,
left: 20,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
DateFormat(tr("date_format")).format(
snapshot.data[index].timestamp
.toDateTime()),
style: TextStyle(color: Colors.white),
),
),
)
],
));
});
},
child: Container(
child: Image.file(
File(snapshot.data[index].thumbPath),
fit: BoxFit.cover,
)),
),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 2),
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
),
);
}
});
}
}
What could be the issue?
I found a solution for this issue. The problem was not the setState({}). It was the return Widget of the FutureBuilder.
I changed
if (!snapshot.hasData || snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
to:
if (!snapshot.hasData || snapshot.connectionState == ConnectionState.waiting) {
return Container(
height: MediaQuery.of(context).size.height,
);
}
I don´t exactly know why, but with this change the page is not jumping to top anymore on setState({})
I try to place an element above another element in flutter. With transform: Matrix4.translationValues it worked to set a negative value, but the element above has a bigger z-index. How could I adjust that? To understand what I need:
This is what I have
This is what I need
My code
class _AlbumDetailState extends State<AlbumDetail> {
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, int>;
final albumID = routeArgs['id'];
final index = routeArgs['index'];
final picturesData = Provider.of<Pictures>(context, listen: true);
Future<void> _addPictureToGallery() async {
final picker = ImagePicker();
final imageFile =
await picker.getImage(source: ImageSource.gallery, maxWidth: 600);
final appDir = await syspath.getApplicationDocumentsDirectory();
final fileName = path.basename(imageFile.path);
final savedImage =
await File(imageFile.path).copy('${appDir.path}/$fileName');
print(savedImage);
picturesData.add(Picture(
album: albumID, path: savedImage.path, timestamp: Timestamp.now()));
}
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text("Album"),
flexibleSpace: FlexibleSpaceBar(
background: Container(
color: Colors.transparent,
child: Hero(
tag: "open_gallery" + index.toString(),
child: Image(
image: NetworkImage('https://placeimg.com/640/480/any'),
fit: BoxFit.cover,
),
),
)),
expandedHeight: 350,
backgroundColor: Colors.green,
pinned: true,
stretch: false,
),
SliverToBoxAdapter(
child: FutureBuilder(
future: picturesData.getPicturesFromAlbum(albumID),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData && snapshot.data.length == 0) {
return Center(
child: Text("Noch keine Bilder vorhanden"),
);
}
if (!snapshot.hasData ||
snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.center,
transform: Matrix4.translationValues(0.0, -75.0, 0.0),
width: MediaQuery.of(context).size.width - 50,
height: 150,
color: Colors.black87,
margin: EdgeInsets.only(top: 50),
child: Text(
"Headline",
style: Theme.of(context)
.textTheme
.headline2
.copyWith(color: theme.colorScheme.onPrimary),
),
),
StaggeredGridView.countBuilder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 6,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) =>
Container(
child: Image.file(
File(snapshot.data[index].path),
fit: BoxFit.cover,
)),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 1),
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
),
],
);
}
}),
)
],
),
);
}
}
The problem: The z-index is not correct on my element. My header is above. How could I adjust the z-index? I know this from CSS. Is there a way to to this with flutter?
One way of achieving overlapping widgets is by using Stack widget. You can check the docs for more details.
try this package https://pub.dev/packages/indexed
https://raw.githubusercontent.com/physia/kflutter/main/indexed/doc/assets/demo.gif
This package allows you to order items inside stack using index like z-index in css
this is example how it works
Indexer(
children: [
Indexed(
index: 100,
child: Positioned(
//...
)
),
Indexed(
index: 1000,
child: Positioned(
//...
)
),
Indexed(
index: 3,
child: Positioned(
//...
)
),
],
);
if you are using bloc of some complex widget you can extands or implement the IndexedInterface class and override index getter:
class IndexedDemo extends IndexedInterface {
int index = 5;
}
or implements
class IndexedDemo extends AnimatedWidget implements IndexedInterface {
int index = 1000;
//...
//...
}
then use it just like Indexed class widget:
Indexer(
children: [
IndexedDemo(
index: 100,
child: Positioned(
//...
)
),
IndexedFoo(
index: 1000,
child: Positioned(
//...
)
),
],
);
Online demo
Video demo
Im new to flutter. Im trying to get items from firestore to be shown in Listview on the app but getting "build function returned null.The offending widget is: StreamBuilder,Build functions must never return null". I just want the list 'post' from firstore shown in listview
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Post App',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Color(0xff543b7a),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(FontAwesomeIcons.hamburger),
),
),
body: StreamBuilder(
stream: Firestore.instance.collection('post').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
Text('Loading');
} else {
return ListView.builder(
itemCount: snapshot.data.document.length,
itemBuilder: (context, index) {
DocumentSnapshot myPost = snapshot.data.documents[index];
return Stack(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: 350.0,
child: Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Material(
color: Colors.white,
elevation: 14.0,
shadowColor: Color(0x802196f3),
child: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: 200.0,
child: Image.network(
'${myPost['image']}',
fit: BoxFit.fill,
),
),
SizedBox(
height: 10.0,
),
Text('${myPost['title']}'),
SizedBox(
height: 10.0,
),
Text('${myPost['subtitle']}'),
],
),
),
),
)
],
);
},
);
},
},
),
);
}
}
[enter image description here][1]
[1]: https://i.stack.imgur.com/QeSyi.png
A build function returned null.The offending widget is: StreamBuilder.Build functions must never return null.
You missed return:
builder: (context, snapshot) {
if (!snapshot.hasData) {
Text('Loading'); // <---- no return here
} else {
return ListView.builder(
itemCount: snapshot.data.documents.length, // <---- documents here
itemBuilder: (context, index) {
DocumentSnapshot myPost = snapshot.data.documents[index];