在Flutter中,如何创建一个带有毛玻璃效果的SliverAppBar?
In Flutter, how to create a SliverAppBar with frosted glass effect?
我想创建一个类似于 Apple News 应用程序中的顶部应用程序栏。
很难在屏幕截图中看到模糊,因为条太细了,但你明白了。
我希望栏通过滚动来扩展和收缩,并在收缩时固定在顶部,就像在屏幕截图中一样,SliverAppBar 完成了所有这些,只是我不能将它包裹在 ClipRect、BackdropFilter 和 Opacity 中创建磨砂玻璃效果,因为 CustomScrollView 仅采用 RenderSliver child 类.
我的测试代码:
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('SliverAppBar'),
elevation: 0,
floating: true,
pinned: true,
backgroundColor: Colors.grey[50],
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
background: Image.network("https://i.imgur.com/cFzxleh.jpg", fit: BoxFit.cover)
),
)
,
SliverFixedExtentList(
itemExtent: 150.0,
delegate: SliverChildListDelegate(
[
Container(color: Colors.red),
Container(color: Colors.purple),
Container(color: Colors.green),
Container(color: Colors.orange),
Container(color: Colors.yellow),
Container(color: Colors.pink,
child: Image.network("https://i.imgur.com/cFzxleh.jpg", fit: BoxFit.cover)
),
],
),
),
],
);
}
有没有办法实现我想要的?
我设法通过将 AppBar
包裹在 SliverPersistentHeader
中来让它工作(这基本上就是 SliverAppBar
所做的)。
忽略未模糊的边缘这是一个 iOS 模拟器错误。
这是一个概念验证代码示例:
class TranslucentSliverAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SliverPersistentHeader(
floating: true,
pinned: true,
delegate: _TranslucentSliverAppBarDelegate(
MediaQuery.of(context).padding,
)
);
}
}
class _TranslucentSliverAppBarDelegate extends SliverPersistentHeaderDelegate {
/// This is required to calculate the height of the bar
final EdgeInsets safeAreaPadding;
_TranslucentSliverAppBarDelegate(this.safeAreaPadding);
@override
double get minExtent => safeAreaPadding.top;
@override
double get maxExtent => minExtent + kToolbarHeight;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return ClipRect(child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 16, sigmaY: 16),
child: Opacity(
opacity: 0.93,
child: Container(
// Don't wrap this in any SafeArea widgets, use padding instead
padding: EdgeInsets.only(top: safeAreaPadding.top),
height: maxExtent,
color: Colors.white,
// Use Stack and Positioned to create the toolbar slide up effect when scrolled up
child: Stack(
overflow: Overflow.clip,
children: <Widget>[
Positioned(
bottom: 0, left: 0, right: 0,
child: AppBar(
primary: false,
elevation: 0,
backgroundColor: Colors.transparent,
title: Text("Translucent App Bar"),
),
)
],
)
)
)
));
}
@override
bool shouldRebuild(_TranslucentSliverAppBarDelegate old) {
return maxExtent != old.maxExtent || minExtent != old.minExtent ||
safeAreaPadding != old.safeAreaPadding;
}
}
我想创建一个类似于 Apple News 应用程序中的顶部应用程序栏。
很难在屏幕截图中看到模糊,因为条太细了,但你明白了。
我希望栏通过滚动来扩展和收缩,并在收缩时固定在顶部,就像在屏幕截图中一样,SliverAppBar 完成了所有这些,只是我不能将它包裹在 ClipRect、BackdropFilter 和 Opacity 中创建磨砂玻璃效果,因为 CustomScrollView 仅采用 RenderSliver child 类.
我的测试代码:
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('SliverAppBar'),
elevation: 0,
floating: true,
pinned: true,
backgroundColor: Colors.grey[50],
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
background: Image.network("https://i.imgur.com/cFzxleh.jpg", fit: BoxFit.cover)
),
)
,
SliverFixedExtentList(
itemExtent: 150.0,
delegate: SliverChildListDelegate(
[
Container(color: Colors.red),
Container(color: Colors.purple),
Container(color: Colors.green),
Container(color: Colors.orange),
Container(color: Colors.yellow),
Container(color: Colors.pink,
child: Image.network("https://i.imgur.com/cFzxleh.jpg", fit: BoxFit.cover)
),
],
),
),
],
);
}
有没有办法实现我想要的?
我设法通过将 AppBar
包裹在 SliverPersistentHeader
中来让它工作(这基本上就是 SliverAppBar
所做的)。
这是一个概念验证代码示例:
class TranslucentSliverAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SliverPersistentHeader(
floating: true,
pinned: true,
delegate: _TranslucentSliverAppBarDelegate(
MediaQuery.of(context).padding,
)
);
}
}
class _TranslucentSliverAppBarDelegate extends SliverPersistentHeaderDelegate {
/// This is required to calculate the height of the bar
final EdgeInsets safeAreaPadding;
_TranslucentSliverAppBarDelegate(this.safeAreaPadding);
@override
double get minExtent => safeAreaPadding.top;
@override
double get maxExtent => minExtent + kToolbarHeight;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return ClipRect(child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 16, sigmaY: 16),
child: Opacity(
opacity: 0.93,
child: Container(
// Don't wrap this in any SafeArea widgets, use padding instead
padding: EdgeInsets.only(top: safeAreaPadding.top),
height: maxExtent,
color: Colors.white,
// Use Stack and Positioned to create the toolbar slide up effect when scrolled up
child: Stack(
overflow: Overflow.clip,
children: <Widget>[
Positioned(
bottom: 0, left: 0, right: 0,
child: AppBar(
primary: false,
elevation: 0,
backgroundColor: Colors.transparent,
title: Text("Translucent App Bar"),
),
)
],
)
)
)
));
}
@override
bool shouldRebuild(_TranslucentSliverAppBarDelegate old) {
return maxExtent != old.maxExtent || minExtent != old.minExtent ||
safeAreaPadding != old.safeAreaPadding;
}
}