flutter - 如何在 SliverAppBar 上重叠 SliverList
问题描述
我试图SliverList
在SliverAppBar
. 类似于这个帖子。我希望 中的图像位于FlexibleSpaceBar
我的SliverList
. 我正在尝试实现以下目标。
我只能得到这样的半径。没有能力重叠SliverList
到他身上SliverAppBar
。
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
floating: false,
expandedHeight: MediaQuery.of(context).size.height * 0.50,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(pet.photos.first)
),
),
SliverList(
delegate: SliverChildListDelegate([
Container(
height: 40,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
),
),
),
]),
)
],
),
);
}
任何方向将不胜感激,谢谢!
解决方案
您可以使用以下小部件,它使用 Stack 和滚动侦听器来实现类似屏幕截图的效果。它基于https://pub.dartlang.org/packages/sliver_fab。
小部件:
import 'package:flutter/material.dart';
class DetailScaffold extends StatefulWidget {
final ScrollController controller;
final ScrollPhysics physics;
final List<Widget> slivers;
final double expandedHeight;
/// Changes edge behavior to account for [SliverAppBar.pinned].
///
/// Hides the edge when the [ScrollController.offset] reaches the collapsed
/// height of the [SliverAppBar] to prevent it from overlapping the app bar.
final bool hasPinnedAppBar;
DetailScaffold({
@required this.expandedHeight,
this.controller,
this.physics,
this.slivers,
this.hasPinnedAppBar = false,
}) {
assert(expandedHeight != null);
assert(hasPinnedAppBar != null);
}
@override
_DetailScaffoldState createState() => _DetailScaffoldState();
}
class _DetailScaffoldState extends State<DetailScaffold> {
ScrollController ctrl;
@override
void initState() {
super.initState();
ctrl = widget.controller ?? ScrollController();
ctrl.addListener(() => setState(() {}));
}
@override
void dispose() {
if (widget.controller == null) {
ctrl.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
CustomScrollView(
controller: ctrl,
physics: widget.physics,
slivers: widget.slivers,
),
_buildEdge(),
],
);
}
_buildEdge() {
var edgeHeight = 12.0;
var paddingTop = MediaQuery.of(context).padding.top;
var defaultOffset =
(paddingTop + widget.expandedHeight) - edgeHeight;
var top = defaultOffset;
var edgeSize = edgeHeight;
if (ctrl.hasClients) {
double offset = ctrl.offset;
top -= offset > 0 ? offset : 0;
if (widget.hasPinnedAppBar) {
// Hide edge to prevent overlapping the toolbar during scroll.
var breakpoint =
widget.expandedHeight - kToolbarHeight - edgeHeight;
if (offset >= breakpoint) {
edgeSize = edgeHeight - (offset - breakpoint);
if (edgeSize < 0) {
edgeSize = 0;
}
top += (edgeHeight - edgeSize);
}
}
}
return Positioned(
top: top,
left: 0,
right: 0,
child: Container(
height: edgeSize,
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.vertical(
top: Radius.circular(12),
),
),
),
);
}
}
使用它:
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
var expandedHeight = 128.0;
return DetailScaffold(
expandedHeight: expandedHeight,
slivers: <Widget>[
SliverAppBar(
expandedHeight: expandedHeight,
flexibleSpace: FlexibleSpaceBar(
background: Container(color: Colors.purple),
),
),
SliverList(
delegate: SliverChildBuilderDelegate((_, i) {
return ListTile(title: Text('Item $i'));
}, childCount: 50),
),
],
);
}
}
推荐阅读
- c# - C# 从其他任何地方访问在运行时构建的数据表
- c++ - 使用带有 Qt 的 Taglib 的未定义引用
- c++ - 在释放内存之前总是重新分配内存是否安全 - C++
- haskell - Haskell - 如何使用函数体中类型签名中指定的类型参数?
- python - 在字典中查找匹配键并用值替换键
- emacs - Emacs:如何定义目录的“书签”变量
- java - 将请求 DTO 映射到实体对象的设计模式?
- swift - 无法将“CGFloat”类型的值转换为闭包结果类型“CGPoint”
- node.js - Sequelize cli 模型创建
- ruby-on-rails-5 - 在 ActiveAdmin 中自定义评论的索引和显示页面