如何使用自定义分割线实现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
相关产品推荐
相关产品推荐

