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

如何使用自定义分割线实现Flutter MultiSplitView区域的折叠/展开?

Flutter MultiSplitView 两大问题解决:区域折叠+分割线按钮显示

问题说明

  • 用MultiSplitView构建可调整多区域页面,拖拽功能正常,但无法实现区域完全折叠
  • 分割线中间的IconButton仅在固定VerticalDivider处可见,MultiSplitView的分割线里按钮不显示

原代码

main.dart

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

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

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

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'MultiSplitView',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
        ),
        home: const MyHomePage(),
      );
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool isClosed = false;
  double width = 200;

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: Text('MultiSplitView collapsible dividers')),
        body: Column(
          children: [
            _buildHorizontalDivider(),
            Divider(),
            Expanded(
              child: Row(
                children: [
                  _buildVerticalDivider(),
                  VerticalDivider(),
                  Expanded(
                    child: MultiSplitView(
                        dividerBuilder: (Axis axis,
                                int index,
                                bool resizable,
                                bool dragging,
                                bool highlighted,
                                MultiSplitViewThemeData themeData) =>
                            _buildVerticalDivider(),
                        initialAreas: [
                          Area(builder: (context, area) => Draft.blue()),
                          Area(builder: (context, area) => Draft.yellow()),
                          Area(builder: (context, area) => Draft.green())
                        ]),
                  ),
                ],
              ),
            ),
          ],
        ),
      );

  Widget _buildHorizontalDivider() => Row(
        children: [
          const Expanded(child: Divider(color: Colors.red)),
          IconButton(
            icon: const Icon(Icons.arrow_drop_up),
            onPressed: () => debugPrint('button up pressed'),
          ),
          const Expanded(child: Divider(color: Colors.red)),
        ],
      );

  Widget _buildVerticalDivider() => Column(
        children: [
          const Expanded(child: VerticalDivider(color: Colors.blue)),
          IconButton(
            icon:
                Icon(isClosed ? Icons.arrow_right : Icons.arrow_left_outlined),
            onPressed: () => setState(() => isClosed = !isClosed),
          ),
          const Expanded(child: VerticalDivider(color: Colors.blue)),
        ],
      );
}

// 补充原代码缺失的Draft类
class Draft extends StatelessWidget {
  final Color color;
  const Draft._(this.color);
  static Draft blue() => Draft._(Colors.blue[100]!);
  static Draft yellow() => Draft._(Colors.yellow[100]!);
  static Draft green() => Draft._(Colors.green[100]!);

  @override
  Widget build(BuildContext context) => Container(color: color);
}

pubspec.yaml

name: untitled
description: "dividers alignment test"
publish_to: 'none'
version: 1.0.0+1

environment:
  sdk: '>=3.4.4 <4.0.0'
dependencies:
  cupertino_icons: ^1.0.6
  flutter:
    sdk: flutter
  multi_split_view: ^3.2.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0

flutter:
  uses-material-design: true

解决方案

1. 实现区域完全折叠

MultiSplitView需要用MultiSplitViewController控制区域尺寸,不能靠自定义变量单独控制:

  • 初始化控制器,给每个区域设置minSize: 0(允许折叠到0宽度/高度)
  • 按钮点击时,切换对应区域的尺寸为0或恢复原始尺寸

2. 修复分割线按钮显示问题

MultiSplitView默认分割线宽度极窄,VerticalDivider默认宽度仅1,IconButton没有显示空间:

  • 用SizedBox给分割线设置固定宽度(比如40)
  • 把分割线和按钮放在容器内,保证按钮有足够显示空间

修改后的完整代码

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

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

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

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'MultiSplitView',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
        ),
        home: const MyHomePage(),
      );
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 初始化控制器,设置初始区域大小,允许最小尺寸为0
  final MultiSplitViewController _controller = MultiSplitViewController(
    areas: [
      Area(size: 200, minSize: 0),
      Area(size: 200, minSize: 0),
      Area(minSize: 0),
    ],
  );

  // 记录每个区域的原始尺寸,用于折叠后恢复
  final Map<int, double?> _originalSizes = {};

  @override
  void initState() {
    super.initState();
    // 保存初始尺寸
    for (int i = 0; i < _controller.areas.length; i++) {
      _originalSizes[i] = _controller.areas[i].size;
    }
  }

  // 切换区域折叠/展开状态
  void _toggleArea(int index) {
    setState(() {
      final currentSize = _controller.areas[index].size;
      if (currentSize == 0) {
        // 恢复原始尺寸
        _controller.areas[index].size = _originalSizes[index];
      } else {
        // 保存当前尺寸,然后折叠为0
        _originalSizes[index] = currentSize;
        _controller.areas[index].size = 0;
      }
    });
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('MultiSplitView collapsible dividers')),
        body: Column(
          children: [
            _buildHorizontalDivider(),
            const Divider(),
            Expanded(
              child: Row(
                children: [
                  _buildVerticalDivider(),
                  const VerticalDivider(),
                  Expanded(
                    child: MultiSplitView(
                      controller: _controller,
                      dividerBuilder: (Axis axis, int index, bool resizable,
                              bool dragging, bool highlighted,
                              MultiSplitViewThemeData themeData) =>
                          _buildMultiSplitVerticalDivider(index),
                      initialAreas: [
                        Area(builder: (context, area) => Draft.blue()),
                        Area(builder: (context, area) => Draft.yellow()),
                        Area(builder: (context, area) => Draft.green())
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      );

  Widget _buildHorizontalDivider() => Row(
        children: [
          const Expanded(child: Divider(color: Colors.red)),
          IconButton(
            icon: const Icon(Icons.arrow_drop_up),
            onPressed: () => debugPrint('button up pressed'),
          ),
          const Expanded(child: Divider(color: Colors.red)),
        ],
      );

  // 固定垂直分割线按钮(原逻辑保留)
  Widget _buildVerticalDivider() => SizedBox(
        width: 40,
        child: Column(
          children: [
            const Expanded(child: VerticalDivider(color: Colors.blue)),
            IconButton(
              icon: const Icon(Icons.arrow_left_outlined),
              onPressed: () => debugPrint('fixed divider button pressed'),
            ),
            const Expanded(child: VerticalDivider(color: Colors.blue)),
          ],
        ),
      );

  // MultiSplitView的自定义分割线,带折叠按钮
  Widget _buildMultiSplitVerticalDivider(int index) => SizedBox(
        width: 40,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Expanded(
              child: Center(
                child: VerticalDivider(color: Colors.blue),
              ),
            ),
            IconButton(
              icon: Icon(
                _controller.areas[index].size == 0
                    ? Icons.arrow_right
                    : Icons.arrow_left_outlined,
              ),
              onPressed: () => _toggleArea(index),
            ),
            const Expanded(
              child: Center(
                child: VerticalDivider(color: Colors.blue),
              ),
            ),
          ],
        ),
      );
}

class Draft extends StatelessWidget {
  final Color color;
  const Draft._(this.color);
  static Draft blue() => Draft._(Colors.blue[100]!);
  static Draft yellow() => Draft._(Colors.yellow[100]!);
  static Draft green() => Draft._(Colors.green[100]!);

  @override
  Widget build(BuildContext context) => Container(color: color);
}

关键改动说明

  • 新增MultiSplitViewController统一控制区域尺寸,设置minSize:0允许完全折叠
  • 给分割线设置固定宽度(40),确保IconButton有足够显示空间
  • 新增_toggleArea方法,处理区域折叠/展开的尺寸切换逻辑
  • 调整分割线布局,用SizedBox包裹并让元素居中,优化显示效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 15:19:55