我正在将Flutter的SliverAppBar
与SliverList
一起使用。
应用程序栏可以很好地与长长的列表一起使用,滚动很多。
但是,如果我有8个项目的中型列表,则应用栏只会部分折叠,直到列表用完为止。从逻辑上讲,滚动停止是因为没有更多的项目,但它在应用栏上留下了非常讨厌的效果,该栏在过渡到折叠的工具栏的中间被留下。
有没有一种方法可以强制列表向上滚动直到工具栏完全折叠?
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
label: Text("Start!"),
icon: Icon(Icons.play_arrow),
backgroundColor: Colors.orange,
elevation: 12,
onPressed: () {
Routing.navigate(
context,
LoggingPage(
workout: _workout,
exercises: workoutExercises,
),
);
},
),
body: CustomScrollView( physics: ScrollPhysics(),
slivers: <Widget>[
SliverAppBar(
actions: <Widget>[
MaterialButton(onPressed: (){}, child: Text("data"),)
],
expandedHeight: 300,
pinned: true,
floating: true,
snap: true,
flexibleSpace: FlexibleSpaceBar(
title: Text(_workout.name),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
buildSliverListItem,
childCount: workoutExercises.length,
),
),
],
),
);
}
答案 0 :(得分:0)
作为解决方法,您可以将窗口小部件与自定义RenderSliver一起使用。必须将其添加到条状列表的末尾。
class CustomRenderSliver extends RenderSliver {
final double _minHeaderHeight;
final double _maxHeaderHeight;
CustomRenderSliver(this._minHeaderHeight, this._maxHeaderHeight);
@override
void performLayout() {
double maxHeight = this.constraints.viewportMainAxisExtent -
(this.constraints.precedingScrollExtent - _maxHeaderHeight) /*height of regular list elements*/ -
_minHeaderHeight;
if (maxHeight < 0.0) maxHeight = 0.0;
this.geometry = SliverGeometry(scrollExtent: maxHeight);
}
}
完整代码
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
final minHeaderHeight = 90.0;
final maxHeaderHeight = 180.0;
List<Widget> slivers = List.generate(4, (index) {
return SliverToBoxAdapter(
child: SizedBox(
height: 100,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 4),
child: Container(
color: Colors.blue,
),
),
),
);
});
// header
slivers.insert(
0, SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: minHeaderHeight,
maxHeight: maxHeaderHeight
),
));
// custom sliver
slivers.add(CustomRenderSliverWidget(minHeaderHeight, maxHeaderHeight));
runApp(MaterialApp(
home: CustomScrollView(
slivers: slivers,
),
));
}
class CustomRenderSliverWidget extends LeafRenderObjectWidget {
final double _minHeaderHeight;
final double _maxHeaderHeight;
CustomRenderSliverWidget(this._minHeaderHeight, this._maxHeaderHeight);
@override
RenderObject createRenderObject(BuildContext context) {
return CustomRenderSliver(_minHeaderHeight, _maxHeaderHeight);
}
}
class CustomRenderSliver extends RenderSliver {
final double _minHeaderHeight;
final double _maxHeaderHeight;
CustomRenderSliver(this._minHeaderHeight, this._maxHeaderHeight);
@override
void performLayout() {
double maxHeight = this.constraints.viewportMainAxisExtent -
(this.constraints.precedingScrollExtent - _maxHeaderHeight) /*height of regular list elements*/ -
_minHeaderHeight;
if (maxHeight < 0.0) maxHeight = 0.0;
this.geometry = SliverGeometry(scrollExtent: maxHeight);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate({
@required this.minHeight,
@required this.maxHeight,
});
final double minHeight;
final double maxHeight;
@override
double get minExtent => minHeight;
@override
double get maxExtent => max(maxHeight, minHeight);
@override
Widget build(BuildContext context, double shrinkOffset,
bool overlapsContent) {
return Container(color: Colors.red,);
}
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return maxHeight != oldDelegate.maxHeight ||
minHeight != oldDelegate.minHeight;
}
}
答案 1 :(得分:0)
我们可以使用基于代码的 NestedScrollView、SliverOverlapAbsorber 和 SliverOverlapInjector,这里有 Andrea 的例子
https://github.com/bizz84/slivers_demo_flutter/blob/master/lib/pages/nested_scroll_view_page.dart。
我们使用 NestedScrollView。首先,我们将 SliverAppbar 嵌入到 headerSliverBuilder 中,并在 SliverAppBar 上方使用 SliverOverlapAbsorber。
接下来,我们将 CustomScrollView 嵌入到 NestedScrollView 主体内的构建器中。我们在主体顶部添加了一个 SliverOverlapInjector。
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
return <Widget>[
SliverOverlapAbsorber(
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
pinned: true,
//floating: true,
stretch: true,
expandedHeight: 300.0,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: const Text('Weather Report'),
background: Image.asset(
'assets/images/logo1.jpg',
fit: BoxFit.cover,
),
),
),
),
];
},
body: SafeArea(
child: Builder(
builder:(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverOverlapInjector(
// This is the flip side of the SliverOverlapAbsorber above.
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i){
return ListTile(
leading: Icon(Icons.wb_sunny),
title: i%2 != 1 ? Text('Sunday ${i+1}') : Text('Monday ${i+1}'),
subtitle: Text('sunny, h: 80, l: 65'),
);
},
childCount: 5
),
),
],
);
}
),
),
),
);