我正在学习Flutter,目前正在尝试制作具有出色滚动效果的主页。我正在尝试使用3个元素实现CustomScrollView:SliverAppBar,水平滚动列表和SliverList。前两个很简单,经过一番挣扎之后,我设法使用SliverPersistentHeader实现了水平滚动列表。
但是,我遇到了一个问题。我希望将SliverAppBar固定,并且将包含水平滚动列表的SliverPersistentHeader浮动。一切正常,除了向下滚动后向上滚动时,浮动元素被固定的元素覆盖。我基本上希望浮动元素“知道”其上方还有另一个元素,并在向上滚动时偏移自身。
您可以在此查看问题,以及我的代码: https://dartpad.dev/32d3f2a890d4a676decb014744fcc9ba
请确保您单击并拖动滚动以查看问题!
我该如何解决?我缺少任何导致此问题的东西吗?
感谢您的光临!
答案 0 :(得分:0)
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
// I had to change this class to a StatefulWidget to be able to listen to the scroll event
class Home extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _HomeState();
}
}
class _HomeState extends State<Home> {
// Here I declared the ScrollController for the CustomScrollView
ScrollController _controller;
// And here is a boolean to check when the user scrolls up or down the view
bool sliverPersistentHeader = false;
@override
void initState() {
super.initState();
// The ScrollController is initialized in the initState and listens for when the user starts scrolling up and changes the boolean value accordingly
_controller = ScrollController();
_controller.addListener(() {
if (_controller.position.userScrollDirection == ScrollDirection.reverse) {
setState(() {
sliverPersistentHeader = false;
});
} else {
setState(() {
sliverPersistentHeader = true;
});
}
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
controller: _controller,
slivers: <Widget>[
SliverAppBar(
floating: true,
pinned: true,
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text('App Title'),
),
),
SliverPersistentHeader(
// The SliverPersisitentHeader checks the boolean value and either pins or unpins the the Header
pinned: sliverPersistentHeader ? true : false,
delegate: CustomSliver(
expandedHeight: 150.0,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(_, index) => Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: Container(
height: 50.0,
color: Colors.amber,
),
),
),
),
],
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Tab1'),
),
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Tab2'),
),
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Tab3'))
],
currentIndex: 0,
),
);
}
}
class CustomSliver extends SliverPersistentHeaderDelegate {
final double expandedHeight;
CustomSliver({@required this.expandedHeight});
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Scrollbar(
child: Container(
color: Theme.of(context).canvasColor,
padding: EdgeInsets.fromLTRB(10.0, 15.0, 0, 5.0),
child: ListView.separated(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.only(right: 10.0, top: 10.0, bottom: 10.0),
child: Container(
width: 100,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(20.0)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.16),
offset: Offset(0, 3.0),
blurRadius: 6.0),
]),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(Icons.navigation),
Text(
'Category',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) {
return SizedBox(width: 5.0);
},
)),
);
}
@override
double get maxExtent => expandedHeight;
@override
double get minExtent => 150.0;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}
我唯一没有做的就是将SliverPersistentHeader设置为动画,希望您可以自己实现。我确定还有其他方法可以实现此目的,但是该解决方案应该可以为您工作。