如何实现带重复平铺背景及视差效果的横向可滚动ListView容器
问题根因
你当前的背景是挂载在宽度等于屏幕宽度的父Container上,DecorationImage的横向重复绘制范围被限制在屏幕宽度内,当横向ListView滚动超出屏幕范围后,背景没有额外的绘制空间,自然无法继续平铺。
修正方案
调整布局结构,将背景与ListView放在同一层级的Stack中,让背景的可绘制宽度匹配ListView的总滚动长度,同时保留视差效果,修正后代码如下:
class _MyHomePageState extends State<MyHomePage> { // 原变量名是_offsetY,实际是横向滚动偏移,修正命名更易读 double _scrollOffsetX = 0.0; late ScrollController _scrollController; // 单个列表项宽度+分隔符宽度,可根据实际业务调整 final double _itemTotalWidth = 80; // 列表总项数 final int _itemCount = 40; _scrollListener() { setState(() { _scrollOffsetX = _scrollController.offset; }); } @override void initState() { _scrollController = ScrollController(); _scrollController.addListener(_scrollListener); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ // 背景层:宽度匹配ListView总滚动长度 Transform.translate( // 视差系数可自行调整,值越小视差效果越明显 offset: Offset(-_scrollOffsetX * 0.3, 0), child: Container( width: _itemCount * _itemTotalWidth, height: double.infinity, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/town_background.jpg'), fit: BoxFit.fitHeight, repeat: ImageRepeat.repeatX, ), ), ), ), // 列表层 ListView.separated( controller: _scrollController, itemCount: _itemCount, separatorBuilder: (_, __) => const Divider(indent: 30), itemBuilder: (_, index) => const Icon(Icons.person, size: 50), scrollDirection: Axis.horizontal, ), ], ), ); } }
修改说明
- 用Stack拆分背景和列表,背景宽度和列表总滚动宽度保持一致,保证背景有足够的空间做横向重复平铺,滚动到列表任何位置都不会出现断层
- 用
Transform.translate处理视差偏移,逻辑更直观,不需要修改DecorationImage的alignment属性,避免和重复平铺逻辑冲突 - 可通过调整视差系数自定义视差滚动幅度,适配不同的设计需求
内容的提问来源于stack exchange,提问作者Kdaydin
相关产品推荐
相关产品推荐

