我正在尝试为容器的背景图像创建 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;
}
}
像垂直滚动页面的美一样工作:)