您需要一个小条来根据滚动偏移设置布局动画.更具体地说,你的情况是SliverPersistentHeader美元.
虽然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;
}
}
可与CustomScrollView一起使用:
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'),
);
}),
)
],
),
);