【发布时间】:2021-10-18 17:39:37
【问题描述】:
我有一个 CustomScrollView 持有
-
SliverPersistentHeader以及 -
SliverList。
我将一些ShapeBorder应用于SliverPersistentHeaderDelegate中返回的Widget。
我现在希望我的“下方”放置SliverList 以使用SliverPersistentHeader 的一些剪切区域,如此屏幕截图所示:
这怎么可能?
这是我的代码:
import 'package:flutter/material.dart';
void main() => runApp(
MediaQuery(data: MediaQueryData(), child: MaterialApp(home: MyApp())));
class MyApp extends StatefulWidget {
// This widget is the root of your application.
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: CustomScrollView(
slivers: <Widget>[
SliverPersistentHeader(
pinned: true,
delegate: CustomSliverPersistentHeader(),
),
SliverList(delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Card(
child: Padding(
padding: EdgeInsets.all(10),
child: Text('text $index'),
));
},
))
],
)));
}
}
class CustomSliverPersistentHeader extends SliverPersistentHeaderDelegate {
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return LayoutBuilder(builder: (context, constraints) {
return Container(
decoration: ShapeDecoration(
color: Colors.amber, shape: CustomShape(shrinkOffset)),
height: constraints.maxHeight,
child: Container());
});
}
@override
bool shouldRebuild(SliverPersistentHeaderDelegate _) => true;
@override
double get maxExtent => 400.0;
@override
double get minExtent => 100.0;
}
class CustomShape extends ShapeBorder {
final double shrinkOffset;
CustomShape(this.shrinkOffset);
@override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
double scrollOffset = 0.0;
if (shrinkOffset <= 100) {
scrollOffset = 100.00 - shrinkOffset;
}
Offset controllPoint1 = Offset(0, rect.size.height - scrollOffset);
Offset endPoint1 = Offset(scrollOffset, rect.size.height - scrollOffset);
Offset controllPoint2 =
Offset(rect.size.width, rect.size.height - scrollOffset);
Offset endPoint2 =
Offset(rect.size.width, rect.size.height - scrollOffset * 2);
return Path()
..lineTo(0, rect.size.height)
..quadraticBezierTo(
controllPoint1.dx, controllPoint1.dy, endPoint1.dx, endPoint1.dy)
..lineTo(rect.size.width - scrollOffset, rect.size.height - scrollOffset)
..quadraticBezierTo(
controllPoint2.dx, controllPoint2.dy, endPoint2.dx, endPoint2.dy)
..lineTo(rect.size.width, 0);
}
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.only(bottom: 0);
@override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
@override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {}
@override
ShapeBorder scale(double t) => this;
}
【问题讨论】:
-
SizedOverflowBox也许? -
我能够以不同的方式向上移动列表,但我们的标题覆盖了 ListView 的顶部项目。我认为最好的方法是使用堆栈。
-
谢谢@pskink!我尝试将它作为父级应用到我的
SliverList,然后必须将其转换为ListView,并且所有这些都必须变为SliverToBoxAdapter,这将我的List向上移动,但它的行为很奇怪,其余的List被切断了。在上面的代码中,您将在何处以及如何应用SizedOverflowBox? -
所以它不是那么聪明;-( - 似乎我最初的想法更好:但是使用
OverflowBox(不是SizedOverflowBox),检查paste.ubuntu.com/p/CQ9BrjQ4j3(老实说我不知道为什么它有效:size: constraints.biggest + Offset(0, 100)- 恕我直言,这里不应该修复100...) -
非常感谢,检查paste.ubuntu.com/p/ctSMCqxFdh - 我更改了
leftRect/rightRect计算,现在它使用size: constraints.biggest + Offset(0, max(0, 100 - shrinkOffset)),而不是size: constraints.biggest + Offset(0, 100),- 恕我直言,现在看起来更好了 - 如果你想要你可以在你的自我回答中使用它