TabBarView без ограниченной высоты
Мне нужно реализовать следующий макет во Flutter.
Когда пользователь прокручивает, я хочу прокрутить весь макет (скрывая заголовок и панель вкладок). Тем не менее, я не могу вкладывать TabBarView в ListView, так как TabBarView не имеет ограниченной высоты, а ListViews не предоставляют ограниченной высоты своим дочерним элементам.
Я уже видел эти вопросы, но у всех них есть неудовлетворительные ответы для этого варианта использования:
- Как я могу иметь TabView с содержимым переменной высоты в Scrollable View с Flutter?: Именно то, что мне было нужно, но единственный ответ не дает никакого конкретного кода о том, как реализовать это, только ссылку на функцию (SliverList), которую я не могу понять, как реализовать.
- Как реализовать sliverAppBar с tabBar: предоставленный код не работает, так как SliverList не принимает конструктор с этой формой (и я попытался адаптировать его для использования делегата без успеха).
- Получение 'Горизонтальная область просмотра получила неограниченную высоту.' с TabBarView во флаттере: этот вариант использования не работает для меня, так как мне нужен весь макет для прокрутки, и в этом ответе заголовок фиксируется в верхней части.
3 ответа
class SliverWithTabBar extends StatefulWidget {
@override
_SliverWithTabBarState createState() => _SliverWithTabBarState();
}
class _SliverWithTabBarState extends State<SliverWithTabBar> with SingleTickerProviderStateMixin {
TabController controller;
@override
void initState() {
super.initState();
controller = TabController(length: 3, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
pinned: false,
backgroundColor: Colors.white,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
background: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 200.0,
width: double.infinity,
color: Colors.grey,
child: FlutterLogo(),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
'Business Office',
style: TextStyle(fontSize: 25.0),
textAlign: TextAlign.left,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
'Open now\nStreet Address, 299\nCity, State',
style: TextStyle(fontSize: 15.0),
textAlign: TextAlign.left,
),
),
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Icon(Icons.share),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Icon(Icons.favorite),
),
],
),
)
],
),
),
expandedHeight: 380.0,
bottom: TabBar(
indicatorColor: Colors.black,
labelColor: Colors.black,
tabs: [
Tab(text: 'POSTS'),
Tab(text: 'DETAILS'),
Tab(text: 'FOLLOWERS'),
],
controller: controller,
),
)
];
},
body: ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return Card(
color: index % 2 == 0 ? Colors.blue : Colors.green,
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: 100.0,
child: Text(
'Flutter is awesome',
style: TextStyle(fontSize: 18.0),
),
),
);
},
),
),
);
}
}
Вы должны искать Sliver
виджеты для достижения NestedScrollView
,
Это дает вам свойство headerSliverBuilder, в котором вы можете разместить некоторые заголовки, которые можно скрыть или закрепить в верхней части экрана при прокрутке виджета тела, в этом конкретном примере ListView
,
Возможно, вы захотите взглянуть на документацию RenderSliver.
В дополнение к ответу Мигеля Рувио, заменяющему ListView в теле на TabBarView, вы получаете почти весь путь за комментарий DR. У меня возникли проблемы с переполнением, когда один из моих виджетов в был заключен в столбец. Замена этого на ListView в этом примере
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Tabs()));
}
class Tabs extends StatefulWidget {
@override
_RoomTabsState createState() => _RoomTabsState();
}
class _RoomTabsState extends State<Tabs> with TickerProviderStateMixin {
var _scrollViewController;
var _tabController;
@override
void initState() {
super.initState();
_scrollViewController = ScrollController();
_tabController = TabController(vsync: this, length: 2);
}
@override
Widget build(BuildContext context) {
return NestedScrollView(
controller: _scrollViewController,
headerSliverBuilder: (context, bool) => [
SliverAppBar(
bottom: TabBar(
controller: _tabController,
tabs: [
Tab(text: "All"),
Tab(text: "Living room"),
],
),
),
],
body: TabBarView(
controller: _tabController,
children: [
ListView(children: [
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
Text("test"),
]),
Text("test"),
],
),
);
}
}
Пожалуйста, попробуйте этот код ниже:
NestedScrollView(
headerSliverBuilder: (context, value) {
return [
SliverToBoxAdapter(
child: Header()
),
SliverToBoxAdapter(
child: TabBar(
controller: _controller,
tabs: [
Tab(icon: Icon(Icons.x)),
Tab(icon: Icon(Icons.y)),
Tab(icon: Icon(Icons.z)),
],
),
),
];
},
body: Container(
child: TabBarView(
controller: _controller,
children: <Widget>[
page1(),
page2(),
page3(),
],
),
),
)