我已经实现了CustomScrollView
,SliverAppBar
和FlexibleSpaceBar
的屏幕,如下所示:
现在,我试图通过复制以下效果来尝试进一步扩展功能:
Expand image to fullscreen on scroll
可以通过在Flutter中使用slivers
来完成类似的事情吗?
基本上,我希望图像在屏幕打开时以其初始大小显示,但是根据滚动方向,它应该设置动画->收缩/淡入淡出(保持列表滚动功能)或扩展到全屏显示(也许是新路径?)。
请帮忙,因为我不确定应该朝哪个方向前进。
这是上述屏幕的代码:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
static const double bottomNavigationBarHeight = 48;
@override
Widget build(BuildContext context) => MaterialApp(
debugShowCheckedModeBanner: false,
home: SliverPage(),
);
}
class SliverPage extends StatefulWidget {
@override
_SliverPageState createState() => _SliverPageState();
}
class _SliverPageState extends State<SliverPage> {
double appBarHeight = 0.0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
physics: AlwaysScrollableScrollPhysics(),
slivers: <Widget>[
SliverAppBar(
centerTitle: true,
expandedHeight: MediaQuery.of(context).size.height * 0.4,
pinned: true,
flexibleSpace: LayoutBuilder(builder: (context, boxConstraints) {
appBarHeight = boxConstraints.biggest.height;
return FlexibleSpaceBar(
centerTitle: true,
title: AnimatedOpacity(
duration: Duration(milliseconds: 200),
opacity: appBarHeight < 80 + MediaQuery.of(context).padding.top ? 1 : 0,
child: Padding(padding: EdgeInsets.only(bottom: 2), child: Text("TEXT"))),
background: Image.network(
'https://images.pexels.com/photos/443356/pexels-photo-443356.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
fit: BoxFit.cover,
),
);
}),
),
SliverList(delegate: SliverChildListDelegate(_buildList(40))),
],
),
);
}
List _buildList(int count) {
List<Widget> listItems = List();
for (int i = 0; i < count; i++) {
listItems.add(
new Padding(padding: new EdgeInsets.all(20.0), child: new Text('Item ${i.toString()}', style: new TextStyle(fontSize: 25.0))));
}
return listItems;
}
}
最佳答案
结合使用CustomScrollView
和SliverPersistentHeader
child: LayoutBuilder(
builder: (context, constraints) {
return CustomScrollView(
controller: ScrollController(initialScrollOffset: constraints.maxHeight * 0.6),
slivers: <Widget>[
SliverPersistentHeader(
pinned: true,
delegate: Delegate(constraints.maxHeight),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(ctx, i) => Container(height: 100, color: i.isOdd? Colors.green : Colors.green[700]),
childCount: 12,
),
),
],
);
},
),
Delegate
使用的SliverPersistentHeader
类如下所示:class Delegate extends SliverPersistentHeaderDelegate {
final double _maxExtent;
Delegate(this._maxExtent);
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
var t = shrinkOffset / maxExtent;
return Material(
elevation: 4,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset('images/bg.jpg', fit: BoxFit.cover,),
Opacity(
opacity: t,
child: Container(
color: Colors.deepPurple,
alignment: Alignment.bottomCenter,
child: Transform.scale(
scale: ui.lerpDouble(16, 1, t),
child: Text('scroll me down',
style: Theme.of(context).textTheme.headline5.copyWith(color: Colors.white)),
),
),
),
],
),
);
}
@override double get maxExtent => _maxExtent;
@override double get minExtent => 64;
@override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}