flutter - Flutter 如何为背景图片创建 parallax 效果

我正在尝试为容器的背景图像创建 parallax 效果。我遵循了本教程 https://docs.flutter.dev/cookbook/effects/parallax-scrolling

但是,我希望背景图像保持在用户滚动的视口广告中。基本上我想实现这种行为https://www.w3schools.com/howto/tryhow_css_parallax_demo.htm

我相信为了实现这一点,我必须修改 ParallaxFlowDelegate 中的 paintChildren 方法

@override
  void paintChildren(FlowPaintingContext context) {
    // Calculate the position of this list item within the viewport.
    final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
    final listItemBox = listItemContext.findRenderObject() as RenderBox;
    final listItemOffset = listItemBox.localToGlobal(
        listItemBox.size.centerLeft(Offset.zero),
        ancestor: scrollableBox);

    // Determine the percent position of this list item within the
    // scrollable area.
    final viewportDimension = scrollable.position.viewportDimension;
    final scrollFraction =
    (listItemOffset.dy / viewportDimension).clamp(0.0, 1.0);

    // Convert the background alignment into a pixel offset for
    // painting purposes.
    final backgroundSize =
        (backgroundImageKey.currentContext!.findRenderObject() as RenderBox)
            .size;

    // Calculate the vertical alignment of the background
    // based on the scroll percent.
    final verticalAlignment = Alignment(0.0, scrollFraction * 2 - 1);

    final listItemSize = context.size;
    final childRect =
    verticalAlignment.inscribe(backgroundSize, Offset.zero & listItemSize);
    // Paint the background.
    context.paintChild(
      0,
      transform:
      Transform.translate(offset: Offset(0.0, childRect.top)).transform,
    );
  }

但我不知道怎么做。

任何帮助将不胜感激 :)

回答1

我只是在搞砸,我当然可以弄清楚。

对于任何感兴趣的人,只需遵循 flutter 开发教程 https://docs.flutter.dev/cookbook/effects/parallax-scrolling ,但将其 ParallaxFlowDelegate 类替换为以下内容:

import 'package:flutter/material.dart';

class ParallaxFlowDelegate extends FlowDelegate {
  final ScrollableState scrollable;
  final BuildContext listItemContext;
  final GlobalKey backgroundImageKey;

  ParallaxFlowDelegate({
    required this.scrollable,
    required this.listItemContext,
    required this.backgroundImageKey,
  }) : super(repaint: scrollable.position);

  @override
  BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) {
    return BoxConstraints.expand(
      width: constraints.maxWidth,
      height: scrollable.position.viewportDimension
    );
  }

  @override
  void paintChildren(FlowPaintingContext context) {
    // Calculate the position of this list item within the viewport.
    final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
    final listItemBox = listItemContext.findRenderObject() as RenderBox;
    final listItemSize = context.size;

    //Gets the offset of the top of the list item from the top of the viewport
    final listItemOffset = listItemBox.localToGlobal(
        listItemBox.size.topCenter(Offset.zero),
        ancestor: scrollableBox);

    // Get the size of the background image
    final backgroundSize =
        (backgroundImageKey.currentContext!.findRenderObject() as RenderBox)
            .size;

    //Gets the vertical size of the viewport (excludes appbars)
    final viewportDimension = scrollable.position.viewportDimension;

    // Determine the percent position of this list item within the
    // scrollable area.
    // - scrollFraction is 1 if listItem's top edge is at the bottom of the
    //   viewport.
    // - scrollFraction is 0 if listItem's top edge is at the top of the
    //   viewport
    // - scrollFraction is -1 if listItem's bottom edge is at the top of the
    //   viewport
    final double scrollFraction, yOffset;
    if(listItemOffset.dy > 0){
      scrollFraction = (listItemOffset.dy / viewportDimension).clamp(0, 1.0);
      yOffset = -scrollFraction * backgroundSize.height;
    }else{
      scrollFraction = (listItemOffset.dy / listItemSize.height).clamp(-1, 0);
      yOffset = -scrollFraction * listItemSize.height;
    }

    // Paint the background.
    context.paintChild(
      0,
      transform:
      Transform.translate(offset: Offset(0, yOffset)).transform,
    );
  }

  @override
  bool shouldRepaint(ParallaxFlowDelegate  oldDelegate) {
    return scrollable != oldDelegate.scrollable ||
        listItemContext != oldDelegate.listItemContext ||
        backgroundImageKey != oldDelegate.backgroundImageKey;
  }
}

像垂直滚动页面的美一样工作:)

相似文章

最新文章