【问题标题】:How to create pageview overlapping effect?如何创建浏览量重叠效果?
【发布时间】:2019-09-22 15:48:07
【问题描述】:

我需要创建一个重叠的综合浏览量集合,但由于项目的绘制/布局顺序,第二页总是显示在第一页的前面。有没有办法创建一个集合列表,其中第一个项目与其他项目重叠?

PAGE BUILDER ->

 Widget buildList(PreloadPageController pageController, List data,
      double currentPosition) {
    return AspectRatio(
      aspectRatio: 12.0 / 15.0,
      child: PreloadPageView.builder(
        itemCount: data.length,
        controller: pageController,
        preloadPagesCount: 2,
        itemBuilder: (context, index) {
          return CardWidget(
              page: index,
              currentPage: currentPosition,
          );
        },
      ),
    );
  }


CARD WIDGET ->
Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, contraints) {
      final double padding = 20.0;

      var delta = currentPage - page;
      var start = padding * delta.abs() * 10;

      var top = padding + padding * max(-delta, 0.0);
      var bottom = padding + padding * max(-delta, 0.0);

      //print(start);
      return Transform.translate(
        offset: Offset(-start, 0),
        child: Container(
          padding: EdgeInsets.only(top: top, bottom: bottom),
          child: ClipRRect(
            borderRadius: BorderRadius.circular(16.0),
            child: Container(
              color: _randomColor(page),
            ),
          ),
        ),
      );
    });
  }

我希望创建一个集合效果,这样第二页就会出现在第一页的后面,但实际上第二页总是与第一页重叠。 我可以在 PageView.builder 中使用reverse,但是这个集合需要是一个无限列表,当它到达末尾时会加载更多数据,而使用reverse,代码会更复杂。

我正在实现这一目标:

但我想要的是红色卡片后面的蓝色卡片。

【问题讨论】:

  • 尝试使用 Stack 小部件。 api.flutter.dev/flutter/widgets/Stack-class.html
  • 嗨!你说使用 Stack 而不是 PageView?我试过了,但是使用 Stack 小部件时,我会消耗大量内存,导致应用程序在开始加载更多数据时崩溃。
  • 这方面有什么更新吗?
  • 我最终使用了 PageView.builder 的 reverse 属性,但我不得不放弃无休止的滚动页面。

标签: flutter dart flutter-layout


【解决方案1】:

所以现在,要创建重叠效果,您正在偏移 next-Page 以使其与 cur-Page 重叠,正如您所提到的,您会发现下一个页面在视觉上over-laps而不是所需的under-lap

那么,除了偏移之外,您是否尝试过裁剪掉 next-Page 的重叠部分?这样可以模拟under-lapping的效果。

现在,我尝试复制您的样本,但我不确定您的 PreloadPageController(可能还有其他细节),因此我的样本可能看起来有问题。此外,我对裁剪小部件并不完全熟悉。但是我遇到了这个可能的解决方案,我所做的只是用另一个 ClipRect 包装它:

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      final double padding = 20.0;

      var delta = widget.currentPage - widget.myPage;
      var start = padding * delta.abs() * 10;

      var top = padding + padding * max(-delta, 0.0);
      var bottom = padding + padding * max(-delta, 0.0);

      return ClipRect(
        child: Transform.translate(
          offset: Offset(-start, 0),
          child: Container(
            padding: EdgeInsets.only(top: top, bottom: bottom),
            child: ClipRRect(
              borderRadius: BorderRadius.circular(16.0),
              child: Container(
                color: redOrBlue(widget.myPage),
              ),
            ),
          ),
        ),
      );
    });
  }

这个额外的ClipRect 基本上剪掉了你的偏移部分。根据需要随意探索和修改!

【讨论】:

  • 嗨,我尝试了您的解决方案,但它的作用是在第一个页面浏览量后面裁剪卡片,并且由于我的实现使卡片与页面浏览量分开,它在第一张和第二张卡片之间产生了间隙(裁剪第二张)。
【解决方案2】:

有一个 Overlay 小部件,但它可能会引起更多的麻烦,尤其是在规模化时。您可以将页面包装在 ClipRect 中,但只有列表末尾的小部件需要它。所以在builder函数中,设置一个bool:

clipNeeded = (controller.page + 0.5) <= index;

然后在新的 ClipRect 小部件中:

clipper: clipNeeded ? CustomRect() : null,

然后你需要创建 CustomRect 类,扩展 CustomClipper&lt;Rect&gt;

所需的精确数学取决于实现,但在这个从左到右滚动的示例中,它将类似于

class CustomRect extends CustomClipper<Rect>{

  @override
  Rect getClip(Size size) {
    double leftLine = /* some calculation */;
    return Rect.fromLTRB(leftLine, 0.0, size.width, size.height);
  }
  @override
  bool shouldReclip(CustomRect oldClipper) {
    return true;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 2014-12-22
    相关资源
    最近更新 更多