side_bar.dart 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. part of "./side_nav.dart";
  2. class _SideBar extends StatefulWidget {
  3. /// 导航Id
  4. final int? navId;
  5. /// 菜单项集合
  6. final List<VSideNavMenuItem> items;
  7. final VSideNavViewController controller;
  8. const _SideBar({
  9. required this.controller,
  10. this.navId,
  11. required this.items,
  12. });
  13. @override
  14. State<StatefulWidget> createState() => _SideBarState();
  15. }
  16. class _SideBarState extends State<_SideBar> {
  17. static const double _cellHegiht = 68.0;
  18. @override
  19. void initState() {
  20. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  21. if (mounted) {
  22. widget.controller.titleChangedEvent.addListener(_onTitleChanged);
  23. }
  24. });
  25. super.initState();
  26. }
  27. @override
  28. void dispose() {
  29. widget.controller.titleChangedEvent.removeListener(_onTitleChanged);
  30. super.dispose();
  31. }
  32. @override
  33. Widget build(BuildContext context) {
  34. return Scrollbar(
  35. thumbVisibility: true,
  36. child: ListView(
  37. padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 12),
  38. children: _buildChildren(context),
  39. ),
  40. );
  41. }
  42. List<Widget> _buildChildren(BuildContext context) {
  43. final children = <Widget>[];
  44. final hasAnyIcon = widget.items.any((e) => e.icon != null);
  45. final divider = Divider(
  46. height: 1,
  47. color: Colors.grey.shade400,
  48. indent: hasAnyIcon ? 36 : 0,
  49. endIndent: 12,
  50. );
  51. final count = widget.items.length;
  52. for (var i = 0; i < count; i++) {
  53. final item = widget.items[i];
  54. if (item.shouldRearrage) {
  55. children.add(const SizedBox(height: 32));
  56. } else if (i > 0) {
  57. children.add(divider);
  58. }
  59. final cell = _buildMenuCell(item);
  60. children.add(cell);
  61. }
  62. return children;
  63. }
  64. Widget _buildMenuCell(VSideNavMenuItem item) {
  65. final hasSection = item.title == widget.controller.currentTitle;
  66. final cell = Padding(
  67. padding: const EdgeInsets.symmetric(horizontal: 12),
  68. child: VListFormCell(
  69. height: _cellHegiht,
  70. leadingIcon: Container(
  71. alignment: Alignment.center,
  72. child: item.icon,
  73. ),
  74. leadingIconWidth: 36,
  75. label: item.title,
  76. onTap: () {
  77. _onItemTap(item, hasSection);
  78. },
  79. ),
  80. );
  81. if (hasSection) {
  82. return _buildSectionItem(cell);
  83. } else {
  84. return cell;
  85. }
  86. }
  87. Widget _buildSectionItem(Widget itemWidget) {
  88. return SizedBox(
  89. height: _cellHegiht,
  90. child: Stack(
  91. children: [
  92. itemWidget,
  93. Positioned.fill(
  94. child: Container(
  95. decoration: BoxDecoration(
  96. borderRadius: GlobalStyles.borderRadius,
  97. color: Theme.of(context).primaryColor.withOpacity(.2),
  98. ),
  99. ),
  100. ),
  101. ],
  102. ),
  103. );
  104. }
  105. void _onTitleChanged(_, String? e) {
  106. setState(() {});
  107. }
  108. void _onItemTap(VSideNavMenuItem item, bool hasSection) {
  109. if (item.onTap != null) {
  110. item.onTap!.call();
  111. return;
  112. }
  113. if (hasSection) {
  114. // 不可重复路由
  115. return;
  116. }
  117. if (item.pageBuilder != null) {
  118. widget.controller.pageChangedEvent.emit(this, item.pageBuilder!);
  119. widget.controller.titleChangedEvent.emit(this, item.title);
  120. }
  121. if (item.route != null) {
  122. Get.offAllNamed(item.route!.name, id: widget.navId);
  123. }
  124. }
  125. }