- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我在我的 CustomScrollView
中使用了一个 SliverPersistentHeader
来拥有一个在用户滚动时会收缩和增长的持久 header ,但是当它达到其最大尺寸时,它会感觉有点僵硬,因为它不会“过度生长”。
这是我想要的行为的视频(来自 Spotify 应用)和我的行为:
.
最佳答案
在寻找解决此问题的方法时,我遇到了三种不同的解决方法:
Stack
,其中包含 CustomScrollView
和一个标题小部件(覆盖在 ScrollView 的顶部),提供一个 ScrollController
给CustomScrollView
并将 Controller 传递给 header 小部件以调整其大小ScrollController
,将其传递给CustomScrollView
,并使用 Controller 的值来调整SliverPersistentHeader的maxExtent
(这就是 Eugene recommended)。我遇到了解决方案 1 和 2 的问题:
CustomScrollView
。这就是我选择解决方案 3 的原因。我确信我实现它的方式不是最好的,但它完全符合我的要求:
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'dart:math' as math;
/// The delegate that is provided to [ElSliverPersistentHeader].
abstract class ElSliverPersistentHeaderDelegate {
double get maxExtent;
double get minExtent;
/// This acts exactly like `SliverPersistentHeaderDelegate.build()` but with
/// the difference that `shrinkOffset` might be negative, in which case,
/// this widget exceeds `maxExtent`.
Widget build(BuildContext context, double shrinkOffset);
}
/// Pretty much the same as `SliverPersistentHeader` but when the user
/// continues to drag down, the header grows in size, exceeding `maxExtent`.
class ElSliverPersistentHeader extends SingleChildRenderObjectWidget {
final ElSliverPersistentHeaderDelegate delegate;
ElSliverPersistentHeader({
Key key,
ElSliverPersistentHeaderDelegate delegate,
}) : this.delegate = delegate,
super(
key: key,
child:
_ElSliverPersistentHeaderDelegateWrapper(delegate: delegate));
@override
_ElPersistentHeaderRenderSliver createRenderObject(BuildContext context) {
return _ElPersistentHeaderRenderSliver(
delegate.maxExtent, delegate.minExtent);
}
}
class _ElSliverPersistentHeaderDelegateWrapper extends StatelessWidget {
final ElSliverPersistentHeaderDelegate delegate;
_ElSliverPersistentHeaderDelegateWrapper({Key key, this.delegate})
: super(key: key);
@override
Widget build(BuildContext context) =>
LayoutBuilder(builder: (context, constraints) {
final height = constraints.maxHeight;
return delegate.build(context, delegate.maxExtent - height);
});
}
class _ElPersistentHeaderRenderSliver extends RenderSliver
with RenderObjectWithChildMixin<RenderBox> {
final double maxExtent;
final double minExtent;
_ElPersistentHeaderRenderSliver(this.maxExtent, this.minExtent);
@override
bool hitTestChildren(HitTestResult result,
{@required double mainAxisPosition, @required double crossAxisPosition}) {
if (child != null) {
return child.hitTest(result,
position: Offset(crossAxisPosition, mainAxisPosition));
}
return false;
}
@override
void performLayout() {
/// The amount of scroll that extends the theoretical limit.
/// I.e.: when the user drags down the list, although it already hit the
/// top.
///
/// This seems to be a bit of a hack, but I haven't found a way to get this
/// information in another way.
final overScroll =
constraints.viewportMainAxisExtent - constraints.remainingPaintExtent;
/// The actual Size of the widget is the [maxExtent] minus the amount the
/// user scrolled, but capped at the [minExtent] (we don't want the widget
/// to become smaller than that).
/// Additionally, we add the [overScroll] here, since if there *is*
/// "over scroll", we want the widget to grow in size and exceed
/// [maxExtent].
final actualSize =
math.max(maxExtent - constraints.scrollOffset + overScroll, minExtent);
/// Now layout the child with the [actualSize] as `maxExtent`.
child.layout(constraints.asBoxConstraints(maxExtent: actualSize));
/// We "clip" the `paintExtent` to the `maxExtent`, otherwise the list
/// below stops moving when reaching the border.
///
/// Tbh, I'm not entirely sure why that is.
final paintExtent = math.min(actualSize, maxExtent);
/// For the layout to work properly (i.e.: the following slivers to
/// scroll behind this sliver), the `layoutExtent` must not be capped
/// at [minExtent], otherwise the next sliver will "stop" scrolling when
/// [minExtent] is reached,
final layoutExtent = math.max(maxExtent - constraints.scrollOffset, 0.0);
geometry = SliverGeometry(
scrollExtent: maxExtent,
paintExtent: paintExtent,
layoutExtent: layoutExtent,
maxPaintExtent: maxExtent,
);
}
@override
void paint(PaintingContext context, Offset offset) {
if (child != null) {
/// This sliver is always displayed at the top.
context.paintChild(child, Offset(0.0, 0.0));
}
}
}
关于flutter - 如何将 SliverPersistentHeader 设置为 "overgrow",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56005307/
背景 我有两个 SliverPersistentHeaders。一个位于 NestedScrollView 内部,其中有一个 TabBar,它应该在滚动时始终可见,所以我将其固定。我还有另一个 Sli
我已经为我遇到的这个问题构建了一个小测试示例。您可以从下面的 gif 中看到 Flutter 应用程序的顶部只有一个标题。当我下拉刷新时,标题不会自行重建。但是,当我向上插入页眉时,页眉会自行重建多次
我正在构建一个使用 SliverPersistentHeader 的 Flutter 应用程序,我添加了一些操作按钮覆盖 SliverPersistentHeader。但是该应用程序遇到了一个问题,即
我在我的 CustomScrollView 中使用了一个 SliverPersistentHeader 来拥有一个在用户滚动时会收缩和增长的持久 header ,但是当它达到其最大尺寸时,它会感觉有点
我在 CustomScrollView 中使用 SliverPersistentHeader 和 SliverList。在到达 SliverList 的第一项(索引:0)之前,我不希望我的 Slive
我正在尝试制作我的 TabBar高度有点大。它仅适用于特定值。这是我的 SliverPersistentHeader : SliverPersistentHeader( pinned: true,
我正在与 Slivers 合作。我有一个 SliverAppBar,然后是一个 SliverPersistentHeader,最后是一个 SliverList。 我想要实现的行为是 SliverApp
我是一名优秀的程序员,十分优秀!