我需要在Flutter中实现以下布局。
当用户滚动时,我希望整个布局都滚动(隐藏标题和标签栏)。但是,我无法将TabBarView嵌套在ListView中,因为TabBarView没有限制的高度,并且ListViews并未为其子代提供限制的高度。
我已经看过这些问题,但是对于此用例,所有问题的答案都不令人满意:
答案 0 :(得分:5)
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 属性,您可以在其中实际放置一些标题,这些标题可能会在滚动小部件时隐藏或固定在屏幕顶部,在此特定示例中,{{ 1}}。
您可能想看一下RenderSliver文档。
答案 1 :(得分:0)
在Miguel Ruvio的回答之上,用TabBarView替换正文中的ListView可以使您几乎按照D.R.的注释进行操作。当我的其中一个小部件包装在一个列中时,确实遇到了一些溢出问题。为此用ListView替换 example
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"),
],
),
);
}
}
来自此github issue。
答案 2 :(得分:0)
请尝试以下代码:
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(),
],
),
),
)