Как я могу иметь TabView с содержимым переменной высоты в Scrollable View с Flutter?
У меня есть TabBar & TabBarView, вложенный в блок. Это связано с тем, что содержимое внутри TabBarView является динамическим, а высота содержимого неизвестна до времени выполнения.
Я не могу вкладывать блок внутрь TabBarView, потому что перед TabBar есть содержимое, которое должно прокручиваться вместе с содержимым TabBarView.
Диаграмма:
Код:
new DefaultTabController(
length: 3,
child: new Block(
children: [
new Container(
height: 200.0,
decoration: new BoxDecoration(
backgroundColor: Colors.blue[500],
),
),
new TabBar(
tabs: <Widget>[
new Tab(text: '1'),
new Tab(text: '2'),
new Tab(text: '3'),
],
),
new TabBarView(
children: [
new Text('one'),
new Text('two'),
new Text('three'),
],
),
],
)
);
Однако область просмотра TabBarView не ограничена и требует виджет-предка с ограниченным ограничением по высоте. К сожалению, блок не дает ограниченную высоту, потому что его прокручиваемый характер.
Я получаю эту ошибку при запуске макета:
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (28715): The following assertion was thrown during performLayout():
I/flutter (28715): RenderList object was given an infinite size during layout.
I/flutter (28715): This probably means that it is a render object that tries to be as big as possible, but it was put
I/flutter (28715): inside another render object that allows its children to pick their own size.
I/flutter (28715): The nearest ancestor providing an unbounded height constraint is: ...
Любые идеи о том, как лучше всего подойти к этому?
3 ответа
Не знаю, что это за блок (ссылка уже не работает). Но, как я вижу из вопроса, вам нужно поместить TableView в какой-то прокручиваемый компонент.
Самое простое решение - использовать контроллер вкладок + контейнер вместо виджета TabView.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
final List<Widget> myTabs = [
Tab(text: 'one'),
Tab(text: 'two'),
Tab(text: 'three'),
];
TabController _tabController;
int _tabIndex = 0;
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
void initState() {
_tabController = TabController(length: 3, vsync: this);
_tabController.addListener(_handleTabSelection);
super.initState();
}
_handleTabSelection() {
if (_tabController.indexIsChanging) {
setState(() {
_tabIndex = _tabController.index;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Container(
height: 120,
child: Center(
child: Text('something on top'),
),
),
TabBar(
controller: _tabController,
labelColor: Colors.redAccent,
isScrollable: true,
tabs: myTabs,
),
Center(
child: [
Text('second tab'),
Column(
children: List.generate(20, (index) => Text('line: $index')).toList(),
),
Text('third tab')
][_tabIndex],
),
Container(child: Text('another component')),
],
),
);
}
}
В настоящее время это решено с помощью пакета expandable_page_view. Будет следующая структура виджета:
SingleChildScrollView(
child: Column(children: [
//... possibly other widgets
TabBar(
controller: _tabController,
tabs: const [
Text('online'),
Text('offline'),
],
),
ExpandablePageView(
controller: _pageController,
children: [
_buildTab(info!.onlineOptions),
_buildTab(info!.offlineOptions),
],
),
],
),
)
Также должно быть два слушателя для подключения логики смены вкладок и страниц:
_tabController = TabController(length: 2, vsync: this);
_pageController = PageController();
_tabController.addListener(() {
if (_tabController.index != _pageController.page?.toInt()) {
_pageController.animateToPage(_tabController.index, duration: const Duration(milliseconds: 100), curve: Curves.ease);
}
});
_pageController.addListener(() {
if (_tabController.index != _pageController.page?.toInt()) {
_tabController.animateTo(_pageController.page?.toInt() ?? 0, duration: const Duration(milliseconds: 100));
}
});
Это будет очень легко сделать с помощью измененного прокручивающегося "скользящего" кода, который в настоящее время находится на https://github.com/flutter/flutter/projects/3.
SliverList https://docs.flutter.io/flutter/widgets/SliverList-class.html предназначен для включения именно такого рода композиции и должен быть готов к общему использованию примерно через две недели.