如何在 SliverAppBar 上重叠 SliverList [英] How to overlap SliverList on a SliverAppBar
问题描述
我试图在 SliverAppBar
上重叠几个像素的 SliverList
.类似于
我只能这样得到半径.无法将 SliverList
重叠到他的 SliverAppBar
上.
@override小部件构建(BuildContext 上下文){返回脚手架(正文:自定义滚动视图(条子:<小部件>[SliverAppBar(浮动:假,扩展高度:MediaQuery.of(context).size.height * 0.50,弹性空间:弹性空间条(背景:Image.network(pet.photos.first)),),银名单(委托:SliverChildListDelegate([容器(身高:40,装饰:盒子装饰(颜色:颜色.红色,边界半径:边界半径.only(左上角:半径.圆形(30),右上角:半径.圆形(30),),),),]),)],),);}
任何方向都将不胜感激,谢谢!
您可以使用以下使用 Stack 和滚动侦听器的小部件来实现类似屏幕截图的效果.它基于 https://pub.dartlang.org/packages/sliver_fab.
小部件:
import 'package:flutter/material.dart';类 DetailScaffold 扩展 StatefulWidget {最终的 ScrollController 控制器;最终的 ScrollPhysics 物理;最终列表<小部件>条子;最终双expandHeight;///更改边缘行为以考虑 [SliverAppBar.pinned].//////当[ScrollController.offset]达到折叠状态时隐藏边缘///[SliverAppBar] 的高度,以防止它与应用栏重叠.final bool hasPinnedAppBar;详细脚手架({@required this.expandedHeight,这个控制器,this.physics,this.slivers,this.hasPinnedAppBar = false,}) {断言(expandedHeight != null);断言(hasPinnedAppBar != null);}@覆盖_DetailScaffoldState createState() =>_DetailScaffoldState();}类 _DetailScaffoldState 扩展状态<DetailScaffold>{滚动控制器 ctrl;@覆盖无效初始化状态(){super.initState();ctrl = widget.controller ??滚动控制器();ctrl.addListener(() => setState(() {}));}@覆盖无效处置(){if (widget.controller == null) {ctrl.dispose();}super.dispose();}@覆盖小部件构建(BuildContext 上下文){返回堆栈(孩子们:<小部件>[自定义滚动视图(控制器: ctrl,物理:widget.physics,条子:widget.slivers,),_buildEdge(),],);}_buildEdge() {变量边缘高度 = 12.0;var paddingTop = MediaQuery.of(context).padding.top;var defaultOffset =(paddingTop + widget.expandedHeight) - edgeHeight;var top = defaultOffset;var edgeSize = edgeHeight;如果(ctrl.hasClients){双偏移 = ctrl.offset;顶部 -= 偏移量 >0 ?偏移量:0;if (widget.hasPinnedAppBar) {//隐藏边缘以防止滚动期间工具栏重叠.var 断点 =widget.expandedHeight - kToolbarHeight - edgeHeight;if (offset >= 断点) {edgeSize = edgeHeight - (偏移量 - 断点);if (edgeSize < 0) {边缘尺寸 = 0;}顶部 += (edgeHeight - edgeSize);}}}返回定位(顶部:顶部,左:0,对:0,孩子:容器(高度:边缘尺寸,装饰:盒子装饰(颜色:Theme.of(context).canvasColor,边界半径:边界半径.vertical(顶部:半径.圆形(12),),),),);}}
使用它:
class Home 扩展 StatelessWidget {@覆盖小部件构建(BuildContext 上下文){变种扩展高度 = 128.0;返回详细信息支架(扩展高度:扩展高度,条子:<小部件>[SliverAppBar(扩展高度:扩展高度,弹性空间:弹性空间条(背景:容器(颜色:Colors.purple),),),银名单(委托:SliverChildBuilderDelegate((_, i) {return ListTile(title: Text('Item $i'));}, childCount: 50),),],);}}
I'm trying to overlap a SliverList
a few pixels over the SliverAppBar
. Similar to this post. I'd like the image in the FlexibleSpaceBar
to go under the radius of my SliverList
.
I'm attempting to achieve the below.
I can only get the radius like so. Without the ability to overlap the SliverList
onto he SliverAppBar
.
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
floating: false,
expandedHeight: MediaQuery.of(context).size.height * 0.50,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(pet.photos.first)
),
),
SliverList(
delegate: SliverChildListDelegate([
Container(
height: 40,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
),
),
),
]),
)
],
),
);
}
Any direction would be appreciated, thanks!
You can use the following widget which uses Stack and scroll listeners to achieve something like the screenshots. It's based on https://pub.dartlang.org/packages/sliver_fab.
The widget:
import 'package:flutter/material.dart';
class DetailScaffold extends StatefulWidget {
final ScrollController controller;
final ScrollPhysics physics;
final List<Widget> slivers;
final double expandedHeight;
/// Changes edge behavior to account for [SliverAppBar.pinned].
///
/// Hides the edge when the [ScrollController.offset] reaches the collapsed
/// height of the [SliverAppBar] to prevent it from overlapping the app bar.
final bool hasPinnedAppBar;
DetailScaffold({
@required this.expandedHeight,
this.controller,
this.physics,
this.slivers,
this.hasPinnedAppBar = false,
}) {
assert(expandedHeight != null);
assert(hasPinnedAppBar != null);
}
@override
_DetailScaffoldState createState() => _DetailScaffoldState();
}
class _DetailScaffoldState extends State<DetailScaffold> {
ScrollController ctrl;
@override
void initState() {
super.initState();
ctrl = widget.controller ?? ScrollController();
ctrl.addListener(() => setState(() {}));
}
@override
void dispose() {
if (widget.controller == null) {
ctrl.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
CustomScrollView(
controller: ctrl,
physics: widget.physics,
slivers: widget.slivers,
),
_buildEdge(),
],
);
}
_buildEdge() {
var edgeHeight = 12.0;
var paddingTop = MediaQuery.of(context).padding.top;
var defaultOffset =
(paddingTop + widget.expandedHeight) - edgeHeight;
var top = defaultOffset;
var edgeSize = edgeHeight;
if (ctrl.hasClients) {
double offset = ctrl.offset;
top -= offset > 0 ? offset : 0;
if (widget.hasPinnedAppBar) {
// Hide edge to prevent overlapping the toolbar during scroll.
var breakpoint =
widget.expandedHeight - kToolbarHeight - edgeHeight;
if (offset >= breakpoint) {
edgeSize = edgeHeight - (offset - breakpoint);
if (edgeSize < 0) {
edgeSize = 0;
}
top += (edgeHeight - edgeSize);
}
}
}
return Positioned(
top: top,
left: 0,
right: 0,
child: Container(
height: edgeSize,
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.vertical(
top: Radius.circular(12),
),
),
),
);
}
}
Using it:
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
var expandedHeight = 128.0;
return DetailScaffold(
expandedHeight: expandedHeight,
slivers: <Widget>[
SliverAppBar(
expandedHeight: expandedHeight,
flexibleSpace: FlexibleSpaceBar(
background: Container(color: Colors.purple),
),
),
SliverList(
delegate: SliverChildBuilderDelegate((_, i) {
return ListTile(title: Text('Item $i'));
}, childCount: 50),
),
],
);
}
}
这篇关于如何在 SliverAppBar 上重叠 SliverList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!