CustomScrollView: Body 在 SliverAppBar 下滚动
CustomScrollView: Body scrolls under SliverAppBar
我在CustomScrollView
内有多个SliverAppBar
,屏幕的body在SliverFillRemaining
内。
顶部的 SliverAppBar 已固定
中间的 SliverAppBar 是一个图像,会随着用户滚动而折叠
Bottom SliverAppBar 是一个固定的 TabBar,在 Image 完全折叠后将保留在 First SliverAppBar 下方
目前的经验是,最初滚动时,body滚动到最低的SliverAppBar下。我已经尝试使用 SliverOverlapAbsorber/Injector,但这只是在 body 的顶部添加了一个 space,这样 space 就会重叠,而不是 body ],但这不是我想要的。
我希望 body 和 SliverAppBars 一起滚动,直到中间的 SliverAppBar 完全折叠,然后我希望 body 滚动。
我已经为此工作了几个小时,你如何阻止 body 在滚动条上重叠?
要实现这种滚动行为,使用起来更容易 NestedScrollView
并注意主应用栏不再位于条子中
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
@override
MyWidgetState createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 2);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('title'),
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {},
),
),
body: NestedScrollView(
floatHeaderSlivers: true,
physics: const BouncingScrollPhysics(),
body: TabBarView(
controller: _tabController,
physics: const NeverScrollableScrollPhysics(),
children: [
SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: List.generate(
1000,
(index) => Text('Tab One: $index'),
),
),
),
SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: List.generate(
1000,
(index) => Text('Tab Two: $index'),
)),
)
],
),
headerSliverBuilder: (context, innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
pinned: true,
floating: false,
elevation: 0,
toolbarHeight: 0,
collapsedHeight: null,
automaticallyImplyLeading: false,
expandedHeight: MediaQuery.of(context).size.height * .4,
flexibleSpace: const FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
background: Placeholder()),
titleSpacing: 0,
primary: false,
),
SliverAppBar(
pinned: true,
forceElevated: true,
primary: false,
automaticallyImplyLeading: false,
expandedHeight: 50,
collapsedHeight: null,
toolbarHeight: 50,
titleSpacing: 0,
title: Align(
alignment: Alignment.topCenter,
child: TabBar(
controller: _tabController,
isScrollable: true,
tabs: [
const Text('Tab One'),
const Text('Tab Two'),
]),
),
),
];
},
),
);
}
}
我在CustomScrollView
内有多个SliverAppBar
,屏幕的body在SliverFillRemaining
内。
顶部的 SliverAppBar 已固定
中间的 SliverAppBar 是一个图像,会随着用户滚动而折叠
Bottom SliverAppBar 是一个固定的 TabBar,在 Image 完全折叠后将保留在 First SliverAppBar 下方
目前的经验是,最初滚动时,body滚动到最低的SliverAppBar下。我已经尝试使用 SliverOverlapAbsorber/Injector,但这只是在 body 的顶部添加了一个 space,这样 space 就会重叠,而不是 body ],但这不是我想要的。
我希望 body 和 SliverAppBars 一起滚动,直到中间的 SliverAppBar 完全折叠,然后我希望 body 滚动。
我已经为此工作了几个小时,你如何阻止 body 在滚动条上重叠?
要实现这种滚动行为,使用起来更容易 NestedScrollView
并注意主应用栏不再位于条子中
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
@override
MyWidgetState createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 2);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('title'),
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {},
),
),
body: NestedScrollView(
floatHeaderSlivers: true,
physics: const BouncingScrollPhysics(),
body: TabBarView(
controller: _tabController,
physics: const NeverScrollableScrollPhysics(),
children: [
SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: List.generate(
1000,
(index) => Text('Tab One: $index'),
),
),
),
SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: List.generate(
1000,
(index) => Text('Tab Two: $index'),
)),
)
],
),
headerSliverBuilder: (context, innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
pinned: true,
floating: false,
elevation: 0,
toolbarHeight: 0,
collapsedHeight: null,
automaticallyImplyLeading: false,
expandedHeight: MediaQuery.of(context).size.height * .4,
flexibleSpace: const FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
background: Placeholder()),
titleSpacing: 0,
primary: false,
),
SliverAppBar(
pinned: true,
forceElevated: true,
primary: false,
automaticallyImplyLeading: false,
expandedHeight: 50,
collapsedHeight: null,
toolbarHeight: 50,
titleSpacing: 0,
title: Align(
alignment: Alignment.topCenter,
child: TabBar(
controller: _tabController,
isScrollable: true,
tabs: [
const Text('Tab One'),
const Text('Tab Two'),
]),
),
),
];
},
),
);
}
}