如果我希望用户在标签栏上添加/删除标签,该如何动态地进行操作?
现在我可以创建一个新标签,但创建时不能跳到正确的页面。
class _Page {
_Page({ this.label, this.colors, this.iconup,this.iconfloatingbutton });
final String label;
final MaterialColor colors;
final IconData iconfloatingbutton;
final IconData iconup;
Color get labelColor => colors != null ? colors.shade300 : Colors.grey.shade300;
bool get fabDefined => colors != null && iconfloatingbutton != null;
Color get fabColor => colors.shade400;
Icon get fabIcon => Icon(iconfloatingbutton);
Key get fabKey => ValueKey<Color>(fabColor);
}
final List<_Page> _allPages = <_Page>[
_Page(label: 'Blue', colors: Colors.indigo,iconup:Icons.text_fields, iconfloatingbutton: Icons.add),
_Page(label: 'Eco', colors: Colors.green,iconup:Icons.text_fields, iconfloatingbutton: Icons.create),
_Page(label: 'No',iconup:Icons.text_fields,),
_Page(label: 'Teal', colors: Colors.teal,iconup:Icons.text_fields, iconfloatingbutton: Icons.add),
];
class TabsFabDemo extends StatefulWidget {
@override
_TabsFabDemoState createState() => _TabsFabDemoState();
}
class _TabsFabDemoState extends State<TabsFabDemo> with SingleTickerProviderStateMixin {
int initPosition = 1;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.green,
child: SafeArea(
child: CustomTabView(
initPosition: initPosition,
itemCount: _allPages.length,
tabBuilder: (context, index) => Tab(text: _allPages[index].label),
pageBuilder: (context, index) => Container(color:Colors.white,child: Text(_allPages[index].label)),
onPositionChange: (index){
print('current position: $index');
},
onScroll: (position) => print("POS : "+'$position'),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
addtab("a",null);
},
child: Icon(Icons.add),
),
);
}
addtab(label,icon){
setState(() {
_allPages.add(new _Page(label: 'Blue', colors: Colors.indigo,iconup:Icons.satellite, iconfloatingbutton: Icons.add));
});
}
}
// ---------------------实施自定义标签------------------
class CustomTabView extends StatefulWidget {
final int itemCount;
final IndexedWidgetBuilder tabBuilder;
final IndexedWidgetBuilder pageBuilder;
final Widget stub;
final ValueChanged<int> onPositionChange;
final ValueChanged<double> onScroll;
final int initPosition;
CustomTabView({
@required this.itemCount,
@required this.tabBuilder,
@required this.pageBuilder,
this.stub,
this.onPositionChange,
this.onScroll,
this.initPosition,
});
@override
_CustomTabsState createState() => _CustomTabsState();
}
class _CustomTabsState extends State<CustomTabView> with TickerProviderStateMixin {
TabController controller;
int _currentCount;
int _currentPosition;
@override
void initState() {
_currentPosition = widget.initPosition ?? 0;
print("INIT POSITION : "+widget.initPosition.toString());
print("INIT POSITION : "+_currentPosition.toString());
controller = TabController(
length: widget.itemCount,
vsync: this,
initialIndex: _currentPosition,
);
controller.addListener(onPositionChange);
controller.animation.addListener(onScroll);
_currentCount = widget.itemCount;
super.initState();
}
@override
void didUpdateWidget(CustomTabView oldWidget) {
if (_currentCount != widget.itemCount) {
print("DID UPDATE POSITION : 0");
controller.animation.removeListener(onScroll);
controller.removeListener(onPositionChange);
controller.dispose();
if (widget.initPosition != null) {
print("DID UPDATE POSITION : 1");
_currentPosition = widget.initPosition;
}
if (_currentPosition > widget.itemCount - 1) {
print("DID UPDATE POSITION : 2");
_currentPosition = widget.itemCount - 1;
_currentPosition = _currentPosition < 0 ? 0 :
_currentPosition;
if (widget.onPositionChange is ValueChanged<int>) {
print("DID UPDATE POSITION : 3");
WidgetsBinding.instance.addPostFrameCallback((_){
if(mounted) {
print("DID UPDATE POSITION : 4");
widget.onPositionChange(_currentPosition);
}
});
}
}
_currentCount = widget.itemCount;
setState(() {
controller = TabController(
length: widget.itemCount,
vsync: this,
initialIndex: _currentPosition,
);
controller.addListener(onPositionChange);
controller.animation.addListener(onScroll);
});
} else if (widget.initPosition != null) {
controller.animateTo(widget.initPosition);
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
controller.animation.removeListener(onScroll);
controller.removeListener(onPositionChange);
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (widget.itemCount < 1) return widget.stub ?? Container();
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
alignment: Alignment.center,
child: TabBar(
isScrollable: true,
controller: controller,
labelColor: Theme.of(context).primaryColor,
unselectedLabelColor: Theme.of(context).hintColor,
indicator: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).primaryColor,
width: 2,
),
),
),
tabs: List.generate(
widget.itemCount,
(index) => widget.tabBuilder(context, index),
),
),
),
Expanded(
child: TabBarView(
controller: controller,
children: List.generate(
widget.itemCount,
(index) => widget.pageBuilder(context, index),
),
),
),
],
);
}
onPositionChange() {
if (!controller.indexIsChanging) {
_currentPosition = controller.index;
if (widget.onPositionChange is ValueChanged<int>) {
widget.onPositionChange(_currentPosition);
}
}
}
onScroll() {
if (widget.onScroll is ValueChanged<double>) {
widget.onScroll(controller.animation.value);
}
}
}
创建标签时,滚动条必须指向新生成的项目
删除标签时,滚动条必须指向上一个元素
答案 0 :(得分:0)
为了动态添加或删除选项卡,您需要在有状态Widget的setState()中调用添加或删除方法。
要将控制器移至新添加的选项卡,只需将initPosition更新为新添加的选项卡索引,如下所示。我刚刚更改了TabsFabDemo类,因为其余所有代码都没问题(CustomTabBar和_Page类的实现)。
class TabsFabDemo extends StatefulWidget {
@override
_TabsFabDemoState createState() => _TabsFabDemoState();
}
class _TabsFabDemoState extends State<TabsFabDemo>
with SingleTickerProviderStateMixin {
int initPosition = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: CustomTabView(
initPosition: initPosition,
itemCount: data.length,
tabBuilder: (context, index) => Tab(text: data[index].label),
pageBuilder: (context, index) =>
Center(child: Text(data[index].label)),
onPositionChange: (index) {
initPosition = index;
},
onScroll: (position) => print('$position'),
),
),
floatingActionButton: Container(
height: 130.0,
width: 80.0,
child: FloatingActionButton(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
data.add(_Page(
label: 'Blue',
colors: Colors.indigo,
iconup: Icons.satellite,
iconfloatingbutton: Icons.add));
int lastIndex = data.length;
initPosition = lastIndex;
});
},
padding: const EdgeInsets.all(0.0),
),
IconButton(
icon: Icon(Icons.remove),
onPressed: () {
setState(() {
data.removeLast();
});
},
padding: const EdgeInsets.all(0.0),
),
],
),
),
),
);
}
}