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

如何实现可循环滚动的横向V形自定义ListView

横向V形循环滚动ListView实现方案

需求回顾

  • 布局为横向V形:采用上排从右到左、下排从左到右的排列方式,形成视觉上的V形结构
  • 支持上下滚动手势触发循环滚动:向下滚动时,末尾元素移至开头,整体元素依次后移;向上滚动时则相反
  • 每个列表项为包含索引文本的容器

问题代码分析

你提供的代码仅通过ClipPath实现了V形裁剪效果,内部是普通垂直ListView,完全未实现横向V形布局、指定滚动逻辑和循环滚动效果,因此不符合需求。

完整实现代码

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('横向V形循环列表')),
        body: const VShapeCircularListView(),
      ),
    );
  }
}

class VShapeCircularListView extends StatefulWidget {
  const VShapeCircularListView({super.key});

  @override
  State<VShapeCircularListView> createState() => _VShapeCircularListViewState();
}

class _VShapeCircularListViewState extends State<VShapeCircularListView> {
  // 维护列表数据,示例为6个元素,对应V形上下各3个
  List<int> _itemIndices = List.generate(6, (index) => index);
  // 单行列数,可根据需求调整
  final int _rowCount = 3;

  @override
  Widget build(BuildContext context) {
    // 拆分数据为上下两行:上排取前rowCount个,下排取后rowCount个
    final topRowItems = _itemIndices.sublist(0, _rowCount);
    final bottomRowItems = _itemIndices.sublist(_rowCount);

    return GestureDetector(
      // 检测垂直滚动手势
      onVerticalDragEnd: (details) {
        setState(() {
          if (details.primaryVelocity! > 0) {
            // 向下滚动:末尾元素移到开头,其余后移
            final lastItem = _itemIndices.removeLast();
            _itemIndices.insert(0, lastItem);
          } else if (details.primaryVelocity! < 0) {
            // 向上滚动:开头元素移到末尾,其余前移
            final firstItem = _itemIndices.removeAt(0);
            _itemIndices.add(firstItem);
          }
        });
      },
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // 上排:从右到左排列,形成V的上半部分
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: topRowItems.reversed.map((index) {
              return _buildItem(index);
            }).toList(),
          ),
          const SizedBox(height: 8),
          // 下排:从左到右排列,形成V的下半部分
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: bottomRowItems.map((index) {
              return _buildItem(index);
            }).toList(),
          ),
        ],
      ),
    );
  }

  // 构建单个列表项容器
  Widget _buildItem(int index) {
    return Container(
      width: 80,
      height: 80,
      margin: const EdgeInsets.symmetric(horizontal: 4),
      decoration: BoxDecoration(
        color: Colors.blueAccent.withOpacity(0.8),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Center(
        child: Text(
          '$index',
          style: const TextStyle(fontSize: 24, color: Colors.white),
        ),
      ),
    );
  }
}

代码说明

  1. 布局结构:通过Column拆分上下两行,上排使用reversed实现从右到左排列,下排正常从左到右排列,组合成V形视觉效果
  2. 循环滚动逻辑:使用GestureDetector监听垂直拖拽结束事件,根据拖拽方向修改数据列表:
    • 向下滚动:移除最后一个元素并插入到列表开头
    • 向上滚动:移除第一个元素并添加到列表末尾
  3. 可扩展性:通过修改_rowCount和_itemIndices的初始化长度,可调整V形的大小和元素数量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:17:09