您需要一个小条来根据滚动偏移设置布局动画。更具体地说,在您的情况下,
sliverPersistentHeader
custommultichildlayout
是不必要的,但是,您可以使用tweens和align/padding/stufactures获得相同的结果。但如果你的布局变得过于复杂,你可以尝试一下。
技巧是使用sliverPersistentHeader给出的滚动偏移量来计算当前的进度。然后使用该行进将元素定位在其原始位置和最终位置之间。
以下是一个原始示例:
class transitionAppbar extends statelesswidget{
最终的小部件虚拟人物;
最终小部件标题;
const transitionAppBar(this.avatar,this.title,key key):super(key:key);
@重写
小部件构建(BuildContext上下文){
返回sliverPersistentHeader(
钉住:真的,
学员:_TransitionAppBardelegate(
化身:化身,
题目:标题,
)
;
}
}
类TransitionAppBardelegate扩展SliverPersistentHeaderDelegate{
最后一次=
大小介于(开始:大小(150.0,150.0),结束:大小(50.0,50.0));
最后一部《阿凡达边缘之旅》=
edgeinsettween(begin:edgeinsets.zero,end:edgeinsets.only(left:10.0));
最后一部影片=
对齐内部(开始:Alignment.TopCenter,结束:Alignment.CenterLeft);
final titlemargintween=边缘设置tween(
开始:边缘集。仅限(顶部:150.0+5.0)
结束:边缘集。仅(左:10.0+50.0+5.0));
最后一个=
AlignmentTween(开始:Alignment.Center,结束:Alignment.CenterLeft);
最终的小部件虚拟人物;
最终小部件标题;
_ transitionAppBardelegate(this.avatar,this.title)
:断言(化身!= NULL)
断言(标题)!= NULL);
@重写
小部件构建
buildContext上下文,Double ShrinkOffset,bool OverlapsContent){
最终进度=收缩偏移/200.0;
final avatarsize=_avatartween.lerp(进度);
final avatarmargin=_avatarmargintween.lerp(进度);
final avatarAlign=_avatarAlignTween.lerp(进度);
final titlemargin=\u titlemargintween.lerp(进度);
final titlealign=\u titlealigntheen.lerp(进度);
返回堆栈(返回堆栈)
配合:stackfit.expand,
子项:<widget>。[
垫料
填充:AvatarMargin,
儿童:对齐
对齐:AvatarAlign,
child:sizedbox.fromsize(大小:avatar size,子:avatar)
)
)
垫料
填充物:奶精,
儿童:对齐
对齐方式:标题对齐,
子级:默认文本样式(
style:theme.of(context).textTheme.title,child:title),
)
)
,
;
}
@重写
double get maxextent=>200.0;
@重写
double get minextent=>100.0;
@重写
bool shouldrebuild(_transitionAppBardelegate oldDelegate){
返回化身!=olddelegate.avatar标题!=olddelegate.title;
}
}
< /代码>
可用于自定义滚动视图:
脚手架(
正文:自定义滚动视图(
长条:<小工具>。[
转换Appbar(
化身:材质(
颜色:颜色。蓝色,
海拔高度:3,
)
标题:文本(“Hello World”),
)
SliverList
委托:SliverChildBuilderDelegate((上下文,索引){
返回ListTile(
标题:文本(“$index”),
;
}
)
,
)
;
< /代码>
在你的情况下。
CustomMultiChildLayout但这不是必需的,您可以使用镊子和对齐/填充/填充物来获得相同的结果。但如果你的布局变得过于复杂,你可以试试看。
技巧是使用sliverPersistentHeader给出的滚动偏移量来计算当前的进度。然后,使用该行进在元素的原始位置和最终位置之间定位元素。
以下是一个原始示例:

class TransitionAppBar extends StatelessWidget {
final Widget avatar;
final Widget title;
const TransitionAppBar({this.avatar, this.title, Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SliverPersistentHeader(
pinned: true,
delegate: _TransitionAppBarDelegate(
avatar: avatar,
title: title,
),
);
}
}
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
final _avatarTween =
SizeTween(begin: Size(150.0, 150.0), end: Size(50.0, 50.0));
final _avatarMarginTween =
EdgeInsetsTween(begin: EdgeInsets.zero, end: EdgeInsets.only(left: 10.0));
final _avatarAlignTween =
AlignmentTween(begin: Alignment.topCenter, end: Alignment.centerLeft);
final _titleMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(top: 150.0 + 5.0),
end: EdgeInsets.only(left: 10.0 + 50.0 + 5.0));
final _titleAlignTween =
AlignmentTween(begin: Alignment.center, end: Alignment.centerLeft);
final Widget avatar;
final Widget title;
_TransitionAppBarDelegate({this.avatar, this.title})
: assert(avatar != null),
assert(title != null);
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
final progress = shrinkOffset / 200.0;
final avatarSize = _avatarTween.lerp(progress);
final avatarMargin = _avatarMarginTween.lerp(progress);
final avatarAlign = _avatarAlignTween.lerp(progress);
final titleMargin = _titleMarginTween.lerp(progress);
final titleAlign = _titleAlignTween.lerp(progress);
return Stack(
fit: StackFit.expand,
children: <Widget>[
Padding(
padding: avatarMargin,
child: Align(
alignment: avatarAlign,
child: SizedBox.fromSize(size: avatarSize, child: avatar),
),
),
Padding(
padding: titleMargin,
child: Align(
alignment: titleAlign,
child: DefaultTextStyle(
style: Theme.of(context).textTheme.title, child: title),
),
)
],
);
}
@override
double get maxExtent => 200.0;
@override
double get minExtent => 100.0;
@override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
return avatar != oldDelegate.avatar || title != oldDelegate.title;
}
}
可用于自定义滚动视图:
Scaffold(
body: CustomScrollView(
slivers: <Widget>[
TransitionAppBar(
avatar: Material(
color: Colors.blue,
elevation: 3.0,
),
title: Text("Hello World"),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return ListTile(
title: Text('$index'),
);
}),
)
],
),
);