转到厨房屏幕。 点击[[蛋糕标签]]。 刷蛋糕项目。 当您进入蛋糕的最后一项时,点击[[菜谱选项卡]]。弹出此错误。
I / flutter(23156):BY动画库引起的异常提示 ╞═════════════════════════════════════════════════ ════════我/扑 (23156):在通知侦听器时引发了以下断言 对于AnimationController:I / flutter(23156): 'package:flutter / src / material / tab_controller.dart':断言失败: 第180行pos 12:“长度> 1”:I / flutter(23156):不正确。 I / flutter(23156):任一断言都指示 框架本身,否则我们应该提供大量的I / flutter (23156):此错误消息中的更多信息可帮助您确定 并解决根本原因。 I / flutter(23156):无论哪种情况, 请通过在GitHub上提交错误报告此声明:I / flutter (23156):
https://github.com/flutter/flutter/issues/new?template=BUG.md I / flutter(23156):I / flutter(23156):当引发异常时, 这是堆栈:I / flutter(23156):#2 TabController.offset = (包:flutter / src / material / tab_controller.dart:180:12)I / flutter (23156):#3 _TabBarViewState._handleScrollNotification (包装:flutter / src / material / tabs.dart:1249:19)I / flutter(23156):#4 NotificationListener._dispatch (package:flutter / src / widgets / notification_listener.dart:127:27) I / flutter(23156):#5 Notification.visitAncestor (package:flutter / src / widgets / notification_listener.dart:45:20) I / flutter(23156):#6
_ScrollNotification&LayoutChangedNotification&ViewportNotificationMixin.visitAncestor (包:flutter / src / widgets / scroll_notification.dart:31:18)I / flutter (23156):#7 Element.visitAncestorElements (包:flutter / src / widgets / framework.dart:3355:39)I / flutter (23156):#8 Notification.dispatch (package:flutter / src / widgets / notification_listener.dart:61:13) I / flutter(23156):#9
ScrollActivity.dispatchScrollUpdateNotification (package:flutter / src / widgets / scroll_activity.dart:96:92)I / flutter (23156):#10 ScrollPosition.didUpdateScrollPositionBy (包裹:flutter / src / widgets / scroll_position.dart:658:14)I / flutter (23156):#11 ScrollPosition.setPixels (包:flutter / src / widgets / scroll_position.dart:219:9)I / flutter (23156):#12 ScrollPositionWithSingleContext.setPixels (软件包:flutter / src / widgets / scroll_position_with_single_context.dart:84:18) I / flutter(23156):#13 DrivenScrollActivity._tick (包:flutter / src / widgets / scroll_activity.dart:629:18)I / flutter (23156):#14
_AnimationController&Animation&AnimationEagerListenerMixin&AnimationLocalListenersMixin.notifyListeners (包:flutter / src / animation / listener_helpers.dart:126:19)I / flutter (23156):#15 AnimationController._tick (包:flutter / src / animation / animation_controller.dart:750:5) I / flutter(23156):#16股票。_tick (package:flutter / src / scheduler / ticker.dart:228:5)I / flutter(23156):17 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback
(包:flutter / src / scheduler / binding.dart:1012:15)I / flutter (23156):#18
_WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleBeginFrame。 (包:flutter / src / scheduler / binding.dart:928:11)I / flutter (23156):#19
__InternalLinkedHashMap&_HashVMBase&MapMixin&_LinkedHashMapMixin.forEach (dart:collection-patch / compact_hash.dart:367:8)I / flutter(23156):#20 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleBeginFrame (package:flutter / src / scheduler / binding.dart:926:17)I / flutter(23156):21 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleBeginFrame
(package:flutter / src / scheduler / binding.dart:856:5)I / flutter(23156):
25 _invoke1(dart:ui / hooks.dart:233:10)I / flutter(23156):#26 _beginFrame(dart:ui / hooks.dart:172:3)I / flutter(23156):(已消除来自类_AssertionError和包dart:async的5帧)I / flutter
(23156):I / flutter(23156):AnimationController通知 听众是:I / flutter(23156):AnimationController#88632(▶ 222.418; for DrivenScrollActivity)
现在返回[[Dishes Tab]]。
cakesController
一种。长度= _index
b。 _previousIndex
= dishesController
C。 _index
= {{0}} _previousIndex
一种。长度= dishesController
。
b。 cakesController
= {{0}}
C。 cakesControllers
= {{0}} cakesController
尝试完成从索引_index
到索引{{0}}的动画,实际上这是_previousIndex
的属性。这会导致错误。
可能的解决方案:
需要确认单击[[Dishes Tab]]后,import 'package:flutter/material.dart';
/***************************** Data Class *************************************************/
/******************************************************************************************/
/*
* Data will display in the TabBarView build method of KitchenBody Class.
*/
class DynamicTabContent {
IconData icon;
String tooTip;
DynamicTabContent.name(this.icon, this.tooTip);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Kitchen',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: Kitchen(),
);
}
}
class Kitchen extends StatefulWidget {
@override
KitchenState createState() => new KitchenState();
}
/***************************** KitchenState Class *************************************************/
/******************************************************************************************/
/*
* KitchenState is the whole working screen.
*/
class KitchenState extends State<Kitchen> with TickerProviderStateMixin {
/*
* These data lists will store data for dishes and cakes tabBarView Widgets.
*/
List<DynamicTabContent> dishes = new List();
List<DynamicTabContent> cakes = new List();
/*
* parentTabsController is helping to move around dishes and cakes.
*/
TabController parentTabsController;
/*
* dishesController is helping to scroll around all the dishes.
*/
TabController dishesController;
/*
* dishesController is helping to scroll around all the cakes.
*/
TabController cakesController;
dishesAndCakesTabsHandler() {
/*
* [[Check]] If parentTabsController index = 0 then it means we are in [[Dishes Tab]].
*/
if (parentTabsController.index == 0) {
/*
* Please read this {{{ if (parentTabsController.index == 1) }}}} condition first
* then comes back to this condition to understand the problem.
* {{{Problem}}}
* Go to [[Cakes Tab]]. Swipe cake items. Tap [[Dishes Tab]] when you are at
* the last item of cakes. Animation length > 1 error occurs.
* {{{Reason}}} When you come back to [[Dishes Tab]].
* cakesController
* Length = {{2}}.
* _index = {{1}}
* _previousIndex = {{0}}
* dishesController
* Length = {{1}}.
* _index = {{0}}
* _previousIndex = {{0}}
* dishesController tried to complete animation from index{{1}} to index{{0}}
* which are actually the properties of cakesController. This cause error given below.
*
* ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞════════════════════════════════════════
* The following assertion was thrown while notifying listeners for AnimationController:
* 'package:flutter/src/material/tab_controller.dart': Failed assertion: line 180 pos 12:
* 'length > 1': is not true.
*
* {{{Now TabBarView data neither change nor swipe.}}}
*
* {{Possible Solution}}
* Need to confirms that when [[Dishes Tab]] clicked, cakesControllers comes back
* to default properties. For example
* cakesController
* Length = {{2}}.
* _index = {{0}}.
* _previousIndex = {{0}}.
*
* {{My Solution}} is implemented below
*/
setState(() {
/*
* animateTo index 0.
*/
this
.cakesController
.animateTo(0, duration: kTabScrollDuration, curve: Curves.ease);
/*
* You can see in console the cakesController current and previous indexes;
*/
print(
'cakesController.index: ' + this.cakesController.index.toString());
print('cakesController.previousIndex: ' +
this.cakesController.previousIndex.toString());
/*
* I completely erase cakesController data then reinitialize it.;
*/
this.cakesController = null;
this.cakesController =
new TabController(length: cakes.length, vsync: this);
});
print('cakesController.index: ' + this.cakesController.index.toString());
print('cakesController.previousIndex: ' +
this.cakesController.previousIndex.toString());
/*
* Initialize dishes again;
*/
setState(() {
/*
* First clear dishes list to stop adding duplicate data.
* Then initialize dishesController.
*/
dishes.clear();
dishes.add(new DynamicTabContent.name(Icons.map, "Taco"));
this.dishesController =
new TabController(length: dishes.length, vsync: this);
});
}
/*
* [[Check]] If parentTabsController index = 1 then it means we are in [[Cakes Tab]].
*/
if (parentTabsController.index == 1) {
/*
* First clear cakes list to stop adding duplicate data.
* Then initialize cakesController.
*/
setState(() {
cakes.clear();
cakes
.add(new DynamicTabContent.name(Icons.cake, "Black Forest Gateau"));
cakes.add(new DynamicTabContent.name(Icons.cake, "Basbousa"));
this.cakesController =
new TabController(length: cakes.length, vsync: this);
});
}
}
@override
void initState() {
super.initState();
print("initState = KitchenTabs");
/*
* Initializing parentTabsController and this initialization [[will never change]].
*/
parentTabsController =
new TabController(initialIndex: 0, length: 2, vsync: this);
/*
* Initializing dishes and dishesController and this initialization will change
* when user came after the visit from [[Cakes to Dishes Tabs]].
*/
dishes.add(new DynamicTabContent.name(Icons.map, "Taco"));
dishesController = new TabController(length: dishes.length, vsync: this);
/*
* Initialization of cakes and cakesController will happen when user tap on [[Cakes Tab]].
*/
}
@override
void dispose() {
print("dispose = KitchenTabs");
dishesController.removeListener(dishesAndCakesTabsHandler);
dishesController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: null,
),
title: Text('Kitchen'),
floating: true,
pinned: true,
bottom: TabBar(
controller: parentTabsController,
onTap: (int index) {
print('*************************************************');
print("Parent Tab: " + index.toString());
print('*************************************************');
dishesAndCakesTabsHandler();
},
tabs: [
Tab(icon: Icon(Icons.fastfood), text: "Dishes"),
Tab(icon: Icon(Icons.cake), text: "Cakes"),
],
),
),
SliverPersistentHeader(
pinned: true,
delegate: TabBarDelegate(
parentTabsController: parentTabsController,
dishesController: dishesController,
cakesController: cakesController,
),
),
];
},
body: TabBarViewWidget(
parentTabsController: parentTabsController,
dishesController: dishesController,
cakesController: cakesController,
dishes: dishes,
cakes: cakes,
),
),
);
}
}
class TabBarViewWidget extends StatefulWidget {
TabBarViewWidget({
this.parentTabsController,
this.dishesController,
this.cakesController,
this.dishes,
this.cakes,
});
final TabController parentTabsController;
final TabController dishesController;
final TabController cakesController;
final List<DynamicTabContent> dishes;
final List<DynamicTabContent> cakes;
State<StatefulWidget> createState() {
return TabBarViewWidgetState();
}
}
/***************************** TabBarViewWidgetState Class *********************************/
/******************************************************************************************/
/*
* TabBarViewWidgetState is returning the TabBarView Widget.
* TabBarViewWidgetState has tabControllers which are initialized from the Kitchen tabControllers.
*/
class TabBarViewWidgetState extends State<TabBarViewWidget> {
@override
void initState() {
print("initState = KitchenBodyState");
super.initState();
}
@override
Widget build(BuildContext context) {
return widget.parentTabsController.index == 0
? TabBarView(
controller: widget.dishesController,
children: widget.dishes.isEmpty
? <Widget>[]
: widget.dishes.map(
(dynamicContent) {
return ListView(
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 50),
width: 200,
height: 400,
child: Column(
children: <Widget>[
Center(
child: Icon(
dynamicContent.icon,
size: 80,
),
),
SizedBox(
height: 20,
),
Center(
child: Text(
dynamicContent.tooTip,
),
),
],
),
),
],
);
},
).toList(),
)
: widget.parentTabsController.index == 1
? TabBarView(
controller: widget.cakesController,
children: widget.cakes.isEmpty
? <Widget>[]
: widget.cakes.map(
(dynamicContent) {
return ListView(
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 50),
width: 200,
height: 400,
child: Column(
children: <Widget>[
Center(
child: Icon(
dynamicContent.icon,
size: 80,
),
),
SizedBox(
height: 20,
),
Center(
child: Text(
dynamicContent.tooTip,
),
),
],
),
),
],
);
},
).toList(),
)
: null;
}
}
/***************************** TabBarDelegate Class *********************************/
/******************************************************************************************/
/*
* TabBarDelegate is returning the TabBar Widget.
* TabBarDelegate has tabBars which are initialized from the Kitchen tabBars.
*/
class TabBarDelegate extends SliverPersistentHeaderDelegate {
TabBarDelegate({
this.parentTabsController,
this.dishesController,
this.cakesController,
});
final TabController parentTabsController;
final TabController dishesController;
final TabController cakesController;
@override
double get minExtent => kToolbarHeight;
@override
double get maxExtent => kToolbarHeight;
getDishName() {
return List<Widget>.generate(
dishesController.length,
(int index) {
print("Dish Tabs");
return new Tab(text: index.toString());
},
);
}
getCakeName() {
return List<Widget>.generate(
cakesController.length,
(int index) {
print("Deal Tabs");
return new Tab(text: index.toString());
},
);
}
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: Theme.of(context).cardColor,
height: kToolbarHeight,
child: TabBar(
controller: parentTabsController.index == 0
? dishesController
: parentTabsController.index == 1 ? cakesController : null,
isScrollable: true,
labelColor: Theme.of(context).accentColor,
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: Theme.of(context).accentColor,
tabs: parentTabsController.index == 0
? getDishName()
: parentTabsController.index == 1 ? getCakeName() : null,
),
);
}
@override
bool shouldRebuild(covariant TabBarDelegate oldDelegate) {
return parentTabsController.index == 0
? oldDelegate.dishesController != dishesController
: parentTabsController.index == 1
? oldDelegate.cakesController != cakesController
: null;
}
}
返回默认属性。例如
1. {{1}}
一种。长度= {{2}}
b。 {{1}} = {{0}}
C。 {{1}} = {{0}}
/ **********只需复制/粘贴即可将代码运行到Flutter项目中********* / / ***************************************************** ********************** /
{{2}}