You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中实现背景图片的反向视差效果?

复刻《孤岛惊魂6》官网视差滚动动画(Flutter实现)

我在《孤岛惊魂6》官网看到了一种视差动画,想在Flutter里复刻它。查了文档和教程也没法精准实现,想要做出官网移动端浏览器的展示效果——图片层叠,滚动时下方图片从下往上反向出现。

我的现有代码如下:

import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    final height = MediaQuery.of(context).size.height;
    final width = MediaQuery.of(context).size.width;
    return Scaffold(
      body: Material(
        child: Stack(
          children: [
            Image.network(
              "https://staticctf.akamaized.net/J3yJr34U2pZ2Ieem48Dwy9uqj5PNUQTn/1mP5aHQYJI5xw08eD2eV0W/7bc890d58c6bcf5efbe8713f147828ae/banner-webasset.jpg",
              height: height,
              fit: BoxFit.fitHeight,
            ),
            SingleChildScrollView(
              child: Column(
                children: [
                  SizedBox(height: height),
                  Image.network(
                    "https://staticctf.akamaized.net/J3yJr34U2pZ2Ieem48Dwy9uqj5PNUQTn/7ad5MGeYDCekqMiS5qRZuK/1005c73ea409e895058d4273d93dcb1a/banner-background_alt.jpg",
                    height: height,
                    width: width,
                    fit: BoxFit.cover,
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

实现方案

要实现这种反向视差滚动效果,核心是监听滚动偏移量,动态调整底层图片的位置,让其移动方向与滚动方向相反。具体实现步骤如下:

1. 监听滚动偏移

使用ScrollController获取实时滚动偏移量,以此控制底层图片的位移。

2. 动态调整图片位置

将滚动偏移量取负值,实现“向下滚动时,底层图片向上移动”的反向动画,达到从下往上显现的效果。

完整代码实现

import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final ScrollController _scrollController = ScrollController();
  double _offset = 0.0;

  @override
  void initState() {
    super.initState();
    // 监听滚动事件,更新偏移量
    _scrollController.addListener(() {
      setState(() {
        _offset = -_scrollController.offset;
      });
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final height = MediaQuery.of(context).size.height;
    final width = MediaQuery.of(context).size.width;
    return Scaffold(
      body: Stack(
        children: [
          // 底层图片:根据滚动偏移动态调整位置
          Positioned(
            top: _offset,
            left: 0,
            right: 0,
            child: Image.network(
              "https://staticctf.akamaized.net/J3yJr34U2pZ2Ieem48Dwy9uqj5PNUQTn/7ad5MGeYDCekqMiS5qRZuK/1005c73ea409e895058d4273d93dcb1a/banner-background_alt.jpg",
              height: height,
              width: width,
              fit: BoxFit.cover,
            ),
          ),
          // 滚动层:触发视差的滚动区域
          SingleChildScrollView(
            controller: _scrollController,
            child: Column(
              children: [
                // 顶部占位,高度与屏幕一致
                SizedBox(height: height),
                // 滚动触发区域,可添加更多内容
                Container(
                  height: height,
                  color: Colors.transparent,
                ),
                // 示例:后续内容
                Container(
                  height: 600,
                  color: Colors.grey[900],
                  child: const Center(
                    child: Text(
                      "更多内容区域",
                      style: TextStyle(color: Colors.white, fontSize: 20),
                    ),
                  ),
                ),
              ],
            ),
          ),
          // 前景图片:固定在顶部,不随滚动移动
          Image.network(
            "https://staticctf.akamaized.net/J3yJr34U2pZ2Ieem48Dwy9uqj5PNUQTn/1mP5aHQYJI5xw08eD2eV0W/7bc890d58c6bcf5efbe8713f147828ae/banner-webasset.jpg",
            height: height,
            fit: BoxFit.fitHeight,
          ),
        ],
      ),
    );
  }
}

关键细节说明

  • 反向位移逻辑:通过_offset = -_scrollController.offset让底层图片与滚动方向反向移动,实现目标视差效果。
  • 层叠顺序:前景图片在最上层保持固定,底层图片在最下层动态位移,中间的滚动层用透明区域不遮挡底层内容。
  • 动画优化:如果需要更平缓的视差效果,可以给偏移量添加系数(比如_offset = -_scrollController.offset * 0.7),降低移动幅度。

内容的提问来源于stack exchange,提问作者Maruf Hassan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:20:48