如何实现类似Louis Vuitton应用的ListView项自定义横向滚动效果
这个效果是卡片居中缩放+纵向偏移视差的横向滚动效果,card_swiper的预设参数无法直接匹配该需求,你可以通过自定义PageView实现,灵活度更高也不会出现依赖兼容问题,具体实现逻辑如下:
实现思路
- 基础滚动容器使用
PageView,设置viewportFraction为0.8,让单页卡片仅占部分宽度,自然露出左右相邻卡片 - 给
PageController添加滚动监听,实时获取当前滚动的页码偏移值 - 每个卡片构建时,根据自身索引和当前滚动偏移值的差值,动态计算缩放比例和纵向偏移量,差越大的卡片缩放比例越小、纵向偏移越大
示例代码
class LVCardScroll extends StatefulWidget { const LVCardScroll({super.key}); @override State<LVCardScroll> createState() => _LVCardScrollState(); } class _LVCardScrollState extends State<LVCardScroll> { final PageController _pageController = PageController(viewportFraction: 0.8); double _currentScrollPage = 0; @override void initState() { super.initState(); // 监听滚动偏移 _pageController.addListener(() { setState(() { _currentScrollPage = _pageController.page ?? 0; }); }); } @override void dispose() { _pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[100], body: PageView.builder( controller: _pageController, // 替换为你的商品实际数量 itemCount: 15, itemBuilder: (context, index) { // 计算当前卡片与滚动位置的差值 double offsetDiff = index - _currentScrollPage; // 限制差值范围避免边缘卡片变形 offsetDiff = offsetDiff.clamp(-1.0, 1.0); // 计算缩放值:居中卡片为1,两侧卡片最小缩放至0.8 double scale = 1 - (offsetDiff.abs() * 0.2); // 计算纵向偏移:居中卡片偏移为0,两侧卡片向下偏移20px double yOffset = offsetDiff.abs() * 20; return Transform.translate( offset: Offset(0, yOffset), child: Transform.scale( scale: scale, child: Container( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 40), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: const [ BoxShadow( color: Colors.black12, blurRadius: 8, offset: Offset(0, 4), ) ] ), // 替换为你的商品项UI child: Center( child: Text("商品 $index", style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w500)), ), ), ), ); }, ), ); } }
你可以根据实际设计需求调整缩放系数、偏移值、viewportFraction参数,即可完全匹配演示效果。
内容的提问来源于stack exchange,提问作者Nabin Dhakal
相关产品推荐
相关产品推荐

