Closed aleksandar-radivojevic closed 5 years ago
And also I forgot to mention another interesting thing, when I set cache_extent=8 (app. half of tabs) very interesting is that swiping between first 8 tabs is laggy while is smooth for the rest of the tabs(7 tabs).
All tests were in release mode. Plugin version: 0.2.2, Flutter version 1.7
cacheExtent full meaning :
/// {@template flutter.rendering.viewport.cacheExtent} /// The viewport has an area before and after the visible area to cache items /// that are about to become visible when the user scrolls. /// /// Items that fall in this cache area are laid out even though they are not /// (yet) visible on screen. The [cacheExtent] describes how many pixels /// the cache area extends before the leading edge and after the trailing edge /// of the viewport. /// /// The total extent, which the viewport will try to cover with children, is /// [cacheExtent] before the leading edge + extent of the main axis + /// [cacheExtent] after the trailing edge. /// /// The cache area is also used to implement implicit accessibility scrolling /// on iOS: When the accessibility focus moves from an item in the visible /// viewport to an invisible item in the cache area, the framework will bring /// that item into view with an (implicit) scroll action. /// {@endtemplate}
you cache so many page , so when you tap on one , cache pages will all rebuild
I understand concept of cache extent but thats not whats happening here.. Please read my issue one more time. Tap on Tab is not a problem in any case, whether cache_extent is equal to 2 or 15. The problem is that when I set cache_extent to be 1 or 2 and when I do SWIPING(sliding with finger to another Tab in ExtendedTabBarView) it has an annoying frame skip at the end of transition between tabs.
Here is a video link, it's really hard to see in video, but on real device is really noticeable
Below is my code for ExtendedTabBar and also for tabs.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:extended_tabs/extended_tabs.dart';
import 'categories/get_categories.dart';
import 'category_template.dart';
class TabControl extends StatefulWidget {
static TabBar mainTabBar = TabBar(
indicatorColor: Colors.indigo,
indicatorSize: TabBarIndicatorSize.label,
labelPadding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 20.0),
labelStyle: TextStyle(
fontSize: 17.0,
),
isScrollable: true,
tabs: buildMenu(),
);
static List<Widget> buildMenu() {
List<Widget> tabs = [];
for (var i = 0; i < CategoriesJson.getCategories.length; i++) {
tabs.add(
Tab(
text: CategoriesJson.getCategories[i]['name'],
),
);
}
return tabs;
}
@override
_TabControlState createState() => _TabControlState();
}
class _TabControlState extends State<TabControl> {
ConnectivityResult connectivityResult;
bool isConnected = true;
Future<bool> checkInternet() async {
connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
setState(() {
isConnected = false;
});
} else {
setState(() {
isConnected = true;
});
}
return isConnected;
}
@override
void initState() {
checkInternet();
super.initState();
}
@override
Widget build(BuildContext context) {
List<Widget> _categories = [];
for (var i = 0; i < CategoriesJson.getCategories.length; i++) {
_categories.add(
CategoryTemplate(
CategoriesJson.getCategories[i]['id'],
),
);
}
return isConnected
? ExtendedTabBarView(
children: _categories,
physics: AlwaysScrollableScrollPhysics(),
cacheExtent: 2,
linkWithAncestor: false,
dragStartBehavior: DragStartBehavior.down,
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.wifi,
color: Colors.grey[700],
size: 120,
),
Text('Problem sa konekcijom.'),
RaisedButton(
child: Text('Pokusaj ponovo'),
onPressed: () {
checkInternet();
}),
],
),
);
}
}
import 'package:flutter_pagewise/flutter_pagewise.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'card_elements/card_template.dart';
import 'models/backend_service.dart';
import 'models/post.dart';
class CategoryTemplate extends StatelessWidget {
final int categoryId;
CategoryTemplate(this.categoryId);
final int pageSize = 10;
@override
Widget build(BuildContext context) {
return PagewiseListView(
pageFuture: (indeks) =>
BackendService.getPosts(indeks * pageSize, categoryId),
pageSize: pageSize,
controller: ScrollController(),
showRetry: true,
loadingBuilder: (context) {
return SpinKitThreeBounce(
size: 28,
color: Theme.of(context).primaryColor,
);
},
itemBuilder: (context, PostModel post, index) {
final parentKey = GlobalKey();
return CardTemplate(post: post, parentKey: parentKey);
},
);
}
}
import 'package:morpheus/page_routes/morpheus_page_route.dart';
import 'package:provider/provider.dart';
import '.././models/post.dart';
import '../post_comments.dart';
import 'date.dart';
import './../models/toast.dart';
import 'featured_media.dart';
import 'share.dart';
import 'title.dart';
import '../offline_article.dart';
class CardTemplate extends StatelessWidget {
final PostModel post;
final GlobalKey parentKey;
CardTemplate({this.post, this.parentKey});
void _handleTap(BuildContext context) {
Navigator.of(context).push(MorpheusPageRoute(
builder: (context) => PostAndComment(post),
parentKey: parentKey,
transitionToChild: true,
));
}
Widget buildSecondCategory() {
if (post.secondCategory != null) {
return Text(post.secondCategory);
}
return null;
}
@override
Widget build(BuildContext context) {
final myDatabase = Provider.of<MyDatabase>(context);
void _addFavorite() {
myDatabase.addFavorite(
Article(
link: post.link,
featuredMediaFull: post.featuredMediaFull,
featuredMediaMedium: post.featuredMediaMedium,
secondCategory: post.secondCategory,
content: post.content,
id: post.id,
firstCategory: post.firstCategory,
title: post.title,
commentCount: post.commentCount),
);
Toast.displayToast('Vest je uspešno dodata u arhivu.');
}
void _deleteFavorite() {
myDatabase.deleteFavorite(post.id);
Toast.displayToast('Vest je uspešno izrisana iz arhive.');
}
return GestureDetector(
key: parentKey,
onTap: () => _handleTap(context),
child: Card(
color: Theme.of(context).cardColor,
child: Container(
padding: const EdgeInsets.fromLTRB(10, 25, 10, 5),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 1,
child: FeaturedMedia(
featuredMedia: post.featuredMediaMedium,
commentCount: post.commentCount.toString(),
),
),
Expanded(
flex: 1,
child: Container(
padding: const EdgeInsets.only(left: 15),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.start,
spacing: 10,
runSpacing: 7,
crossAxisAlignment: WrapCrossAlignment.start,
children: <Widget>[
Container(
padding: const EdgeInsets.symmetric(
horizontal: 7.0, vertical: 3.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
color: Theme.of(context).accentColor,
),
child: Text(post.firstCategory ?? ''),
),
Container(
padding: EdgeInsets.symmetric(
vertical:
post.secondCategory != null ? 3.0 : 0,
horizontal: 7.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
color: Theme.of(context).accentColor,
),
child: buildSecondCategory(),
)
],
),
CardTitle(post.title),
],
),
),
),
]),
Row(
children: <Widget>[
Expanded(child: CardDate(post.date)),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
StreamBuilder<bool>(
stream: myDatabase.isFavorite(post.id),
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData && snapshot.data) {
return IconButton(
icon: Icon(Icons.bookmark),
onPressed: _deleteFavorite,
);
}
return IconButton(
onPressed: _addFavorite,
icon: Icon(Icons.bookmark_border),
);
},
),
CardShare(post.title, post.link)
],
),
),
],
),
],
),
),
),
);
}
}
Hi there. You can try add logs when initState
or dispose
or build
, try to figure out the reason why it'll cause the lagging action. Also please provider a smaller demo, which means the smallest demo that can reproduce this issue. Thanks.
Hey guys, I've found out what is the problem.
Let's say for example that we have a news app with 3 tabs and we set cacheExtent = 1. As soon as we start swiping(sliding) from first to second tab, third tab is (pre)loading and thats causing the lag. Transition between second and third tab is going to be smooth(also from second to first), because it has nothing in front to preload.
If we set cacheExtent=3 everything will run smooth, because it has nothing to preload, but this is expensive when we have lot of tabs.
Maybe if you can change the speed of transition between tabs on swiping or force TabBar to start preloading next Tab after the swiping animation has finished, thats my ideas on this. I'm hoping that you guys can find a workaround this, because I really can't.
Here is the small demo that will demonstrate the problem. https://github.com/aleksandar-radivojevic/extended_tabs_issue
Thank you for your further investigation.
First thing I want to say is as many flutter'er will done, which is mixed those code for business with the UI thread, may cause app looks not so smooth in some cases. I'm not saying that your code is bad or something, but you may try to solve this issue in this way.
Second is cacheExtent
might not doing what we expected, we're currently working on it and try to find another method to implement 'page cache' properly. Before that, I personally recommend you leave this value without setting it.
We'll try to run your example when we have time for coding, cause now in China is the Mid-Autumn festival. Will be back soon :)
Thank you very much Alex, I'm aware of my code structure and will fix that and come back with results.
Just one more question, is there a way to increase speed of swiping through tabs? I think that that will solve the problem, because when I tap on Tab, animation is both fast and smooth, I am just wondering is there a way to make swiping speed equal like is on tapping? And to be always consistent, no matter how fast or slow user slides with finger.
Have a great time on festival.
@aleksandar-radivojevic That's kinda easy XD, with the constant value kTabScrollDuration
in material constants. It's 300 milliseconds by default, overwritten the _warpToCurrentIndex
which is implement at here /lib/src/tabs.dart#L177 might work.
Tried like this, but no success..
void changeTab() {
TabControl.tabController.animateTo(
TabControl.tabController.index,
duration: Duration(milliseconds: 100),
curve: Curves.bounceInOut,
);
}
@override
void initState() {
TabControl.tabController =
TabController(length: CategoriesJson.getCategories.length, vsync: this);
Home.scrollController = ScrollController(initialScrollOffset: 0);
TabControl.tabController.addListener(changeTab);
super.initState();
}
Can we use this plugin with PageView?
@aleksandar-radivojevic Sorry about our busy in our work. PageView is the default implement.
@aleksandar-radivojevic I thought that maybe you'll get better performance if you using a PageView
rather than TabBarView
for your code, cause PageView
's pages will not keep alive when they are not selected, and when TabBarView
animate to some index, all pages between them will run initState
again.
I've tried it but no success. Its the same. One thing that gain some kind of success is using Future.delayed() with duration of 300ms(which is duration of switching between tabs when swiping/sliding) for my network call inside Tab. But I use same call for fetching more posts bottom(Pagewise ListView package), so thats the problem..
@aleksandar-radivojevic And that's definitely what I was told you before, the request stuck UI thread. So I think this issue can be closed, and you can investigate about how to avoid this situation.
Main Reason for this lag is highly discussed here, if you want to know more then visit here .... https://github.com/flutter/flutter/issues/27680
Reasonable alternative can be their ... [https://medium.com/fluttervn/making-bottom-tabbar-with-flutter-5ff82e8defe0](visit here)
I'm building a news app(wordpress as a backend) that has 15 tabs(categories) in ExtendedTabBarView and when I set cache_extent=15, swiping(sliding with finger) between tabs is very smooth but the scrolling is laggy(probably due to high memory usage because it has to preload and cache 15 tabs with 10 post per tab), BUT when I set cache_extent=2, app works fine but swiping between tabs is laggy at the end of animation(transition), while when I TAP on single tab transition between tabs is always smooth, both on cache_extent 2 and 15. What can be the issue with this, I'm not saying thats your plugin a problem, but I need help, I'm struggling with this whole week. :D :D
If you need code sample or anything, just ask I will respond immediately. Keep up the good work. (: