flutter如何为ListView.builder添加垂直滚动条?

想通过ListView.builder写一个表格组件,本来自带垂直滚动条,但是还需要水平滚动条,所以就想着添加一个自定义的水平滚动条CupertinoScrollbar,但是写好发现垂直滚动条只有在水平滚动条滚动到最右侧才能显示,并且一个自带的和一个添加的CupertinoScrollbar两者样式不太统一,就想着两个滚动条都自定义算了,但是目前只正确添加了水平滚动条,垂直滚动条不知道怎么添加,求助!

当前效果图:(水平、垂直都可以滚动,但是目前只能看到水平滚动条)

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

  @override
  State<AppGrid> createState() => _AppTableState();
}

List<String> rows = List.generate(20, (index) => "Item ${index + 1}");
Color tableBgColor = const Color.fromARGB(10, 235, 224, 223); // 表格背景色
Color borderColor = Colors.blue; // 边框颜色
double rowheight = 50; // 行高
double borderWidth = 1; // 边框宽度
double tableWrapperPadding = 8;

class _AppTableState extends State<AppGrid> {
  final _horizontalScrollController = ScrollController();
  final _verticalController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return CupertinoScrollbar(
      controller: _horizontalScrollController,
      thumbVisibility: true,
      child: SingleChildScrollView(
        controller: _horizontalScrollController,
        scrollDirection: Axis.horizontal,
        child: SizedBox(
          width: 2000,
          child: Container(
            padding: EdgeInsets.only(bottom: tableWrapperPadding),
            width: double.infinity,
            decoration: BoxDecoration(
              color: tableBgColor,
              border: Border.all(color: borderColor, width: borderWidth),
            ),
            child: ScrollConfiguration(
              behavior: ScrollConfiguration.of(
                context,
              ).copyWith(scrollbars: false),
              child: ListView.builder(
                controller: _verticalController,
                itemCount: rows.length,
                itemExtent: rowheight,
                // cacheExtent: 20,
                itemBuilder: (BuildContext ctxt, int index) {
                  return Container(
                    child: Row(children: [Text('data_${index + 1}')]),
                  );
                },
              ),
            ),
          ), // 你的 ListView.builder
        ),
      ),
    );
  }
}

找到一个组件:https://pub-web.flutter-io.cn/packages/single_child_two_dimen...

阅读 366
1 个回答
  1. 使用两个独立的 ScrollController
  2. 正确嵌套 CupertinoScrollbar,外层控制垂直滚动,内层控制水平滚动
  3. 为水平滚动条指定 scrollbarOrientation: CupertinoScrollbarOrientation.bottom
  4. 移除了原代码中禁用滚动条的 ScrollConfiguration

完整代码

IOS平台

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

  @override
  State<AppGrid> createState() => _AppTableState();
}

List<String> rows = List.generate(20, (index) => "Item ${index + 1}");
Color tableBgColor = const Color.fromARGB(10, 235, 224, 223); // 表格背景色
Color borderColor = Colors.blue; // 边框颜色
double rowheight = 50; // 行高
double borderWidth = 1; // 边框宽度
double tableWrapperPadding = 8;

class _AppTableState extends State<AppGrid> {
  final _horizontalScrollController = ScrollController();
  final _verticalScrollController = ScrollController();

  @override
  void dispose() {
    _horizontalScrollController.dispose();
    _verticalScrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 外层使用垂直方向的CupertinoScrollbar
    return CupertinoScrollbar(
      controller: _verticalScrollController,
      thumbVisibility: true, // 始终显示滚动条
      child: Container(
        padding: EdgeInsets.only(bottom: tableWrapperPadding),
        decoration: BoxDecoration(
          color: tableBgColor,
          border: Border.all(color: borderColor, width: borderWidth),
        ),
        // 内层使用水平方向的CupertinoScrollbar
        child: CupertinoScrollbar(
          controller: _horizontalScrollController,
          thumbVisibility: true, // 始终显示滚动条
          // 设置为水平滚动条
          scrollbarOrientation: CupertinoScrollbarOrientation.bottom,
          child: SingleChildScrollView(
            controller: _horizontalScrollController,
            scrollDirection: Axis.horizontal,
            child: SizedBox(
              width: 2000,
              child: ListView.builder(
                controller: _verticalScrollController,
                itemCount: rows.length,
                itemExtent: rowheight,
                // 不要禁用滚动条,让外层的CupertinoScrollbar控制垂直滚动条
                itemBuilder: (BuildContext ctxt, int index) {
                  return Container(
                    child: Row(
                      children: List.generate(
                        10, 
                        (colIndex) => Container(
                          width: 200,
                          alignment: Alignment.center,
                          decoration: BoxDecoration(
                            border: Border(
                              right: BorderSide(color: borderColor, width: borderWidth),
                              bottom: BorderSide(color: borderColor, width: borderWidth),
                            ),
                          ),
                          child: Text('数据_${index + 1}_${colIndex + 1}'),
                        ),
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Windows平台

import 'package:flutter/material.dart';

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

  @override
  State<AppGrid> createState() => _AppTableState();
}

List<String> rows = List.generate(20, (index) => "Item ${index + 1}");
Color tableBgColor = const Color.fromARGB(10, 235, 224, 223); // 表格背景色
Color borderColor = Colors.blue; // 边框颜色
double rowheight = 50; // 行高
double borderWidth = 1; // 边框宽度
double tableWrapperPadding = 8;

class _AppTableState extends State<AppGrid> {
  final _horizontalScrollController = ScrollController();
  final _verticalScrollController = ScrollController();

  @override
  void dispose() {
    _horizontalScrollController.dispose();
    _verticalScrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 外层使用垂直方向的Scrollbar
    return Scrollbar(
      controller: _verticalScrollController,
      thumbVisibility: true, // 始终显示滚动条
      child: Container(
        padding: EdgeInsets.only(bottom: tableWrapperPadding),
        decoration: BoxDecoration(
          color: tableBgColor,
          border: Border.all(color: borderColor, width: borderWidth),
        ),
        // 内层使用水平方向的Scrollbar
        child: Scrollbar(
          controller: _horizontalScrollController,
          thumbVisibility: true, // 始终显示滚动条
          // 设置为水平滚动条
          scrollbarOrientation: ScrollbarOrientation.bottom,
          child: SingleChildScrollView(
            controller: _horizontalScrollController,
            scrollDirection: Axis.horizontal,
            child: SizedBox(
              width: 2000,
              child: ListView.builder(
                controller: _verticalScrollController,
                itemCount: rows.length,
                itemExtent: rowheight,
                // 不要禁用滚动条,让外层的Scrollbar控制垂直滚动条
                itemBuilder: (BuildContext ctxt, int index) {
                  return Container(
                    child: Row(
                      children: List.generate(
                        10, 
                        (colIndex) => Container(
                          width: 200,
                          alignment: Alignment.center,
                          decoration: BoxDecoration(
                            border: Border(
                              right: BorderSide(color: borderColor, width: borderWidth),
                              bottom: BorderSide(color: borderColor, width: borderWidth),
                            ),
                          ),
                          child: Text('数据_${index + 1}_${colIndex + 1}'),
                        ),
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
        ),
      ),
    );
  }
}

使用InteractiveViewer

import 'package:flutter/material.dart';

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

  @override
  State<AppGrid> createState() => _AppTableState();
}

List<String> rows = List.generate(20, (index) => "Item ${index + 1}");
Color tableBgColor = const Color.fromARGB(10, 235, 224, 223); // 表格背景色
Color borderColor = Colors.blue; // 边框颜色
double rowheight = 50; // 行高
double borderWidth = 1; // 边框宽度
double tableWrapperPadding = 8;

class _AppTableState extends State<AppGrid> {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(tableWrapperPadding),
      decoration: BoxDecoration(
        color: tableBgColor,
        border: Border.all(color: borderColor, width: borderWidth),
      ),
      child: InteractiveViewer(
        constrained: false,
        scaleEnabled: false, // 禁用缩放功能,只保留滚动
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: List.generate(
            rows.length,
            (index) => Container(
              height: rowheight,
              child: Row(
                children: List.generate(
                  10,
                  (colIndex) => Container(
                    width: 200,
                    height: rowheight,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                      border: Border(
                        right: BorderSide(color: borderColor, width: borderWidth),
                        bottom: BorderSide(color: borderColor, width: borderWidth),
                      ),
                    ),
                    child: Text('数据_${index + 1}_${colIndex + 1}'),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题