I have a gridview.builder that fetches images from an API, images are already compressed to a max of 70kb each. I am also using pagination usin to fetch more data. When the grid crosses 30+ images the scrolling becomes choppy and when I go to a page by clicking on any image and then I come back many images load again everything again. I am maintaining the state using IndexedStack. And back animation is also stuttering. What am I doing wrong here?
Gridview Builder Code:
GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: postsList.posts.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 3,
mainAxisSpacing: 3,
),
itemBuilder: (context, index) {
return ProfilePostImageCard(
length: postsList.posts.length,
post: postsList.posts[index],
stringOfPostID: stringOfPostID,
);
})
ProfilePostImageCard
class ProfilePostImageCard extends StatelessWidget {
final ProfilePostModel post;
final String stringOfPostID;
final int length;
ProfilePostImageCard({Key key, this.post, this.stringOfPostID, this.length}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfileFeedsPage(
currentMemberImage: CurrentUser().currentUser.image,
listOfPostID: stringOfPostID,
postID: post.postId,
logo: CurrentUser().currentUser.logo,
country: CurrentUser().currentUser.country,
memberID: CurrentUser().currentUser.memberID,
)));
},
child: Container(
child: Stack(
children: [
AspectRatio(
aspectRatio: 1,
child: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: post.postAllImage,
),
),
post.dataMultiImage == 1
? Positioned.fill(
child: Align(
alignment: Alignment.topRight,
child: Padding(
padding: EdgeInsets.all(6.0),
child: Image.asset(
"assets/images/multiple.png",
height: 2.5.h,
),
)),
)
: Container(),
post.postType == "Video" || post.postType == "svideo"
? Positioned.fill(
child: Align(
alignment: Alignment.topRight,
child: Padding(
padding: EdgeInsets.all(6.0),
child: Icon(
Icons.video_collection,
color: Colors.white,
size: 2.5.h,
))),
)
: Container(),
],
),
),
);
}
}
Full Code
SmartRefresher(
enablePullDown: true,
enablePullUp: selectedIndex == 1 ? false : true,
header: CustomHeader(
builder: (context, mode) {
return Container(
child: Center(child: loadingAnimation()),
);
},
),
footer: CustomFooter(
builder: (BuildContext context, LoadStatus mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text("");
} else if (mode == LoadStatus.loading) {
body = loadingAnimation();
} else if (mode == LoadStatus.failed) {
body = Container(
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(color: Colors.black, width: 0.7),
),
child: Padding(
padding: EdgeInsets.all(12.0),
child: Icon(CustomIcons.reload),
));
} else if (mode == LoadStatus.canLoading) {
body = Text("");
} else {
body = Text("No more Data");
}
return Container(
height: 55.0,
child: Center(child: body),
);
},
),
controller: _postRefreshController,
onRefresh: _onRefresh,
onLoading: () {
if (selectedIndex == 0) {
_onLoading();
} else {
print("blog");
}
},
child: ListView(
physics: AlwaysScrollableScrollPhysics(),
children: [
profileLoaded == true
? ProfileCard(
userImage: userImage,
totalPosts: totalPosts,
followers: followers,
following: following,
bio: bio,
name: name,
shortcode: shortcode,
list: list,
)
: Container(),
TabBar(
indicatorColor: Colors.black,
tabs: <Tab>[
Tab(
child: Text(
"Posts",
style: blackBold.copyWith(color: Colors.black, fontSize: 10.0.sp),
),
),
Tab(
child: Text(
"Blogs",
style: blackBold.copyWith(color: Colors.black, fontSize: 10.0.sp),
),
),
Tab(
child: Text(
"Channel",
style: blackBold.copyWith(color: Colors.black, fontSize: 10.0.sp),
),
),
],
controller: _tabController,
onTap: (int index) {
setState(() {
selectedIndex = index;
_tabController.animateTo(index);
});
},
),
IndexedStack(
children: <Widget>[
GestureDetector(
onHorizontalDragUpdate: (details) {
if (details.delta.dx < 0) {
setState(() {
_tabController.animateTo(1);
selectedIndex = 1;
});
} else if (details.delta.dx > 0) {
setState(() {
_tabController.animateTo(2);
selectedIndex = 2;
});
}
},
child: Visibility(
child: Container(
child: hasPosts == true
? GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: postsList.posts.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 3,
mainAxisSpacing: 3,
),
itemBuilder: (context, index) {
return ProfilePostImageCard(
length: postsList.posts.length,
post: postsList.posts[index],
stringOfPostID: stringOfPostID,
);
})
: Container(),
),
maintainState: true,
visible: selectedIndex == 0,
),
),
GestureDetector(
onHorizontalDragUpdate: (details) {
if (details.delta.dx < 0) {
setState(() {
_tabController.animateTo(2);
selectedIndex = 2;
});
} else if (details.delta.dx > 0) {
setState(() {
_tabController.animateTo(0);
selectedIndex = 0;
});
}
},
child: Visibility(
child: Container(
child: hasPosts == true
? Column(
children: [
ListView.builder(
controller: widget.scrollController,
shrinkWrap: true,
//physics: NeverScrollableScrollPhysics(),
itemCount: blogsList.blogs.length,
itemBuilder: (context, index) {
var blog = blogsList.blogs[index];
return PersonalBlogCard(
blog: blog,
index: index,
lastIndex: blogsList.blogs.length - 1,
);
},
),
Padding(
padding: EdgeInsets.symmetric(vertical: 2.0.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
if (currentPage > 1) {
setState(() {
hasBlogs = false;
currentPage = --currentPage;
});
getBlogs();
}
},
child: CircleAvatar(
radius: 3.0.h,
backgroundColor: primaryBlueColor,
child: Icon(
Icons.arrow_back_ios_outli