В Flutter реализовать макет вкладок легко и просто. Это простой пример из официального документация:
import 'package:flutter/material.dart';
void main() {
runApp(new TabBarDemo());
}
class TabBarDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
bottom: new TabBar(
tabs: [
new Tab(icon: new Icon(Icons.directions_car)),
new Tab(icon: new Icon(Icons.directions_transit)),
new Tab(icon: new Icon(Icons.directions_bike)),
],
),
title: new Text('Tabs Demo'),
),
body: new TabBarView(
children: [
new Icon(Icons.directions_car),
new Icon(Icons.directions_transit),
new Icon(Icons.directions_bike),
],
),
),
),
);
}
}
Но вот в чем дело: я хочу получить индекс активной вкладки, чтобы применить некоторую логику к определенным вкладкам. Я ищу документацию, но не могу понять. Ребята, вы можете помочь и спасибо?
Вся суть DefaultTabController
в том, что он сам по себе управляет вкладками.
Если вам нужно какое-то настраиваемое управление вкладками, используйте вместо этого TabController
.
С TabController
у вас есть доступ к гораздо большему количеству информации, включая текущий индекс.
class MyTabbedPage extends StatefulWidget {
const MyTabbedPage({Key key}) : super(key: key);
@override
_MyTabbedPageState createState() => new _MyTabbedPageState();
}
class _MyTabbedPageState extends State<MyTabbedPage>
with SingleTickerProviderStateMixin {
final List<Tab> myTabs = <Tab>[
new Tab(text: 'LEFT'),
new Tab(text: 'RIGHT'),
];
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = new TabController(vsync: this, length: myTabs.length);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
bottom: new TabBar(
controller: _tabController,
tabs: myTabs,
),
),
body: new TabBarView(
controller: _tabController,
children: myTabs.map((Tab tab) {
return new Center(child: new Text(tab.text));
}).toList(),
),
);
}
}
В этом примере как получить индекс ?? Я попытался добавить список, но после создания определенного представления вкладки слушатель печатал индекс, который я хочу получить, прежде чем создавать макет конкретной вкладки. Любая идея?
только с состоянием?
Привет, @sarveshchavan, ты нашел какое-нибудь решение?
Чтобы получить индекс вкладок, просто выполните _tabController.index
В этом случае использование StatefulWidget
и State
- не лучшая идея.
Вы можете получить текущий индекс по DefaultTabController.of(context).index;
.
Следуйте коду:
...
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(~), Tab(~)
]
),
actions: [
// At here you have to get `context` from Builder.
// If you are not sure about this, check InheritedWidget document.
Builder(builder: (context){
final index = DefaultTabController.of(context).index;
// use index at here...
})
]
)
У меня сработало обертывание всего Scaffold
внутри Builder
.
Спасибо, это все, что я искал. ???
Это должен быть принятый ответ. Самое простое решение, требующее наименьшего количества изменений кода.
Благодаря примеру Реми Русселе вы можете это сделать, вот такой код:
_tabController.index
Это вернет текущий индекс позиции вашего TabBarView
Вы можете получить доступ к текущему индексу, когда вкладка выбрана событием onTap для TabBar.
TabBar(
onTap: (index) {
//your currently selected index
},
tabs: [
Tab1(),
Tab2(),
]);
Это не работает должным образом, если пользователь меняет вкладки, проводя пальцем по экрану. Только если они действительно нажимают на панель вкладок.
Просто примените слушателя к TabController.
// within your initState() method
_tabController.addListener(_setActiveTabIndex);
void _setActiveTabIndex() {
_activeTabIndex = _tabController.index;
}
Этот код предоставит вам указатель активной вкладки, а также сохранит указатель вкладки для будущего использования, а когда вы вернетесь на страницу вкладки, будет отображаться предыдущая активная страница.
import 'package:flutter/material.dart';
void main() {
runApp(new TabBarDemo());
}
class TabBarDemo extends StatelessWidget {
TabScope _tabScope = TabScope.getInstance();
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new DefaultTabController(
length: 3,
index: _tabScope.tabIndex, //
child: new Scaffold(
appBar: new AppBar(
bottom: new TabBar(
onTap: (index) => _tabScope.setTabIndex(index), //current tab index
tabs: [
new Tab(icon: new Icon(Icons.directions_car)),
new Tab(icon: new Icon(Icons.directions_transit)),
new Tab(icon: new Icon(Icons.directions_bike)),
],
),
title: new Text('Tabs Demo'),
),
body: new TabBarView(
children: [
new Icon(Icons.directions_car),
new Icon(Icons.directions_transit),
new Icon(Icons.directions_bike),
],
),
),
),
);
}
}
class TabScope{ // singleton class
static TabScope _tabScope;
int tabIndex = 0;
static TabScope getInstance(){
if (_tabScope == null) _tabScope = TabScope();
return _tabScope;
}
void setTabIndex(int index){
tabIndex = index;
}
}
Вы можете добавить слушателя для прослушивания изменений на вкладках, как показано ниже.
tabController = TabController(vsync: this, length: 4)
..addListener(() {
setState(() {
switch(tabController.index) {
case 0:
// some code here
case 1:
// some code here
}
});
});
Не забудьте перезапустить приложение после этого, вместо того, чтобы использовать горячую перезагрузку. Поскольку горячая перезагрузка не обязательно снова запускает initState для вашего экрана.
Используя DefaultTabController
, вы можете легко получить текущий индекс независимо от того, меняет ли пользователь вкладки с помощью смахивание или кран на панели вкладок.
Важно: вы должны обернуть свой Scaffold
внутри Builder
, и тогда вы сможете получить индекс вкладки с помощью DefaultTabController.of(context).index
внутри Scaffold
.
Пример:
DefaultTabController(
length: 3,
child: Builder(builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
bottom: TabBar(
isScrollable: true,
tabs: [Text('0'), Text('1'), Text('2')]),
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
print(
'Current Index: ${DefaultTabController.of(context).index}');
},
),
);
}),
),
Новое рабочее решение
Я предлагаю вам использовать TabController
для дополнительных настроек. Чтобы получить индекс активной вкладки, вы должны использовать _tabController.addListener
и _tabController.indexIsChanging
.
Используйте этот полный фрагмент кода:
class CustomTabs extends StatefulWidget {
final Function onItemPressed;
CustomTabs({
Key key,
this.onItemPressed,
}) : super(key: key);
@override
_CustomTabsState createState() => _CustomTabsState();
}
class _CustomTabsState extends State<CustomTabs>
with SingleTickerProviderStateMixin {
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
TabController _tabController;
int _activeIndex = 0;
@override
void initState() {
super.initState();
_tabController = TabController(
vsync: this,
length: myTabs.length,
);
}
@override
void dispose() {
super.dispose();
_tabController.dispose();
}
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
_tabController.addListener(() {
if (_tabController.indexIsChanging) {
setState(() {
_activeIndex = _tabController.index;
});
}
});
return Container(
color: Colors.white,
child: TabBar(
controller: _tabController,
isScrollable: true,
indicatorPadding: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
indicator: BoxDecoration(
borderRadius: BorderRadius.circular(10.0), color: Colors.green),
tabs: myTabs
.map<Widget>((myTab) => Tab(
child: Container(
width: width / 3 -
10, // - 10 is used to make compensate horizontal padding
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color:
_activeIndex == myTabs.indexOf(myTab)
? Colors.transparent
: Color(0xffA4BDD4),
),
margin:
EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
child: Align(
alignment: Alignment.center,
child: Text(
myTab.text,
style: TextStyle(color: Colors.white),
),
),
),
))
.toList(),
onTap: widget.onItemPressed,
),
);
}
}
Ответ на вашу проблему здесь введите описание ссылки здесь