我已使用补间动画在容器中使用自定义应用栏设计了此布局,以实现所示效果。
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
TransitionAppBar(
title: Container(
margin: EdgeInsets.symmetric(horizontal: 20.0, vertical: 0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(5.0))),
child: Row(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20.0, right: 10.0),
child: Icon(Icons.search)),
Expanded(
child: TextFormField(
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none)))
])))
];
},
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text("${index}"),
);
},
),
),
);
}
class TransitionAppBar extends StatelessWidget {
final Widget title;
const TransitionAppBar({this.title, Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SliverPersistentHeader(
pinned: true, delegate: _TransitionAppBarDelegate(title: title));
}
}
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
final _titleMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(top: 100.0 + 5.0),
end: EdgeInsets.only(top: 10.0 + 50.0 + 5.0),
);
final _titleAlignTween =
AlignmentTween(begin: Alignment.center, end: Alignment.topCenter);
final Widget title;
_TransitionAppBarDelegate({this.title}) : assert(title != null);
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
final progress = shrinkOffset / 200.0;
final titleMargin = _titleMarginTween.lerp(progress);
final titleAlign = _titleAlignTween.lerp(progress);
return Stack(
children: <Widget>[
AnimatedContainer(
duration: Duration(milliseconds: 100),
height: progress * 110,
color: Colors.redAccent,
),
Padding(
padding: titleMargin,
child: Align(
alignment: titleAlign,
child: title,
),
)
],
);
}
@override
double get maxExtent => 180.0;
@override
double get minExtent => 150.0;
@override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
return title != oldDelegate.title;
}
}
此代码可以正常工作,但是目前您可以在下面的屏幕截图中看到,列表的第一个元素(即0)位于搜索文本表单字段的后面。 但是我要实现的是在Transition App Bar动画完成后滚动列表。