使用 SliverAppBar 设计这个动画
Posted
技术标签:
【中文标题】使用 SliverAppBar 设计这个动画【英文标题】:Design this animation using SliverAppBar flutter 【发布时间】:2020-04-06 20:12:31 【问题描述】:Here's what I want to build 但我能够做到这一点
通过以下代码,
@override
Widget build(BuildContext context)
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled)
return [
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: false,
flexibleSpace: Container(
padding: EdgeInsets.all(10),
height: 160,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: Text(
'Hello World',
)),
Padding(
padding: EdgeInsets.only(top: 16),
child: Image.asset(
'assets/images/banner.png',
),
),
],
),
),
),
];
,
body: ListView.builder(),
),
);
我曾尝试使用灵活扩展的 SliverAppBar,但无法实现。
更新 - 列表的第一个元素在文本字段后面。我只想在动画完成时滚动
【问题讨论】:
就个人而言,我认为仅使用 SliversAppBar 是不可能的。您需要创建自己的自定义应用栏,然后使用 Hero Animation(将文本从左侧移动到中心)、AnimatedContainer(降低容器高度)、AnimationController、FadeTransition,并监听您的 Listview 控制器。有点高级。 让我尝试一下,实施后会回复您。谢谢@FadhliS 我将尝试使用我提到的所有小部件为您提供解决方案。我也不容易达到你想要的效果。您可以阅读我发现的这篇博客文章,以了解动画的工作原理,并希望对您有所帮助。 smashingmagazine.com/2019/10/animation-apps-flutter 【参考方案1】:更新的答案,
@override
Widget build(BuildContext context)
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
TransitionAppBar(
extent: 250,
avatar: Text("Rancho"),
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(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
cursorColor: Colors.black,
autofocus: false,
style: TextField_Style,
decoration: InputDecoration(
filled: true,
fillColor: Colors.transparent,
contentPadding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
hintText: "Search",
border: InputBorder.none,
disabledBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
),
focusedBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
)),
),
)
]),
),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index)
return Container(
color: Colors.blue,
child: ListTile(
title: Text("$indexa"),
));
, childCount: 25))
],
),
);
.
class TransitionAppBar extends StatelessWidget
final Widget avatar;
final Widget title;
final double extent;
TransitionAppBar(this.avatar, this.title, this.extent = 250, Key key) : super(key: key);
@override
Widget build(BuildContext context)
return SliverPersistentHeader(
pinned: true,
delegate: _TransitionAppBarDelegate(
avatar: avatar,
title: title,
extent: extent > 200 ? extent : 200
),
);
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate
final _avatarMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(bottom: 70, left: 30),
end: EdgeInsets.only(left: 0.0, top: 30.0));
final _avatarAlignTween =
AlignmentTween(begin: Alignment.bottomLeft, end: Alignment.topCenter);
final Widget avatar;
final Widget title;
final double extent;
_TransitionAppBarDelegate(this.avatar, this.title, this.extent = 250)
: assert(avatar != null),
assert(extent == null || extent >= 200),
assert(title != null);
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent)
double tempVal = 34 * maxExtent / 100;
final progress = shrinkOffset > tempVal ? 1.0 : shrinkOffset / tempVal;
print("Objechjkf === $progress $shrinkOffset");
final avatarMargin = _avatarMarginTween.lerp(progress);
final avatarAlign = _avatarAlignTween.lerp(progress);
return Stack(
children: <Widget>[
AnimatedContainer(
duration: Duration(milliseconds: 100),
height: shrinkOffset * 2,
constraints: BoxConstraints(maxHeight: minExtent),
color: Colors.redAccent,
),
Padding(
padding: avatarMargin,
child: Align(
alignment: avatarAlign,
child: avatar
),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: Align(
alignment: Alignment.bottomCenter,
child: title,
),
)
],
);
@override
double get maxExtent => extent;
@override
double get minExtent => (maxExtent * 68) / 100;
@override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate)
return avatar != oldDelegate.avatar || title != oldDelegate.title;
【讨论】:
元素类型“_TransitionAppBarDelegate”不能分配给列表类型“Widget”。插入 headerSliverBuilder 时出现此错误 一切正常,但如果你看到,列表的第一个元素在动画完成之前在文本字段后面。我只想在动画完成后滚动列表。 这只是演示代码,请根据需要自定义代码。 我管理了所有内容,但是如何避免列表的第一个元素在动画完成之前落后于 textformfield,因为动画取决于进度。请帮忙。 @nardeepsinh-vaghela 非常好,这正是我要找的东西啊哈太棒了,谢谢!以上是关于使用 SliverAppBar 设计这个动画的主要内容,如果未能解决你的问题,请参考以下文章