自定义 Boxmenu

效果

boxmenu

sample 代码

class Boxmenu extends FreshalRoute{

  
  get title => 'Boxmenu';

  
  Widget buildMyRouteContent(BuildContext context) {

    /// Boxmenu的宽高比列
    const double aspectRatio = 0.75;

    ///  portrait:Taller than wide,
    ///  landscape:Wider than tall.
    ///  简单的说portrait就是竖屏,landscape是横屏
    ///  如果横屏放3列,如果竖屏放4列
    final int columnCount = (MediaQuery.of(context).orientation == Orientation.portrait) ? 3 : 4;
    /// TODO : move to constants.dart
    /// 创建菜单项目
    List<BoxMenuItem> menus = [
      BoxMenuItem("ELECTRICITY", FontAwesomeIcons.bolt, (){print('electricity pressed');}),
      BoxMenuItem("WATER", FontAwesomeIcons.tint, (){print('water pressed');}),
      BoxMenuItem("MOBILE", FontAwesomeIcons.mobile, (){print('mobile pressed');}),
      BoxMenuItem("ELECTRICITY", FontAwesomeIcons.bolt, (){print('electricity pressed');}),
      BoxMenuItem("WATER", FontAwesomeIcons.tint, (){print('water pressed');}),
      BoxMenuItem("MOBILE", FontAwesomeIcons.mobile, (){print('mobile pressed');}),
      BoxMenuItem("ELECTRICITY", FontAwesomeIcons.bolt, (){print('electricity pressed');}),
      BoxMenuItem("WATER", FontAwesomeIcons.tint, (){print('water pressed');}),
      BoxMenuItem("MOBILE", FontAwesomeIcons.mobile, (){print('mobile pressed');}),
      BoxMenuItem("ELECTRICITY", FontAwesomeIcons.bolt, (){print('electricity pressed');}),
      BoxMenuItem("WATER", FontAwesomeIcons.tint, (){print('water pressed');}),
    ];
    return SingleChildScrollView(
      child: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
          final double columnWidth = constraints.biggest.width /
              columnCount.toDouble();
          print(columnWidth);
          /// 最高225,随便定的一般现在都有1280了,所以至少能一屏幕显示4行菜单
          final double rowHeight = math.min(225.0, columnWidth * aspectRatio);
          print(rowHeight);
          /// 11个项目,每行3个,应该就是4行。
          final int rowCount = (menus.length / columnCount).ceil();

          return Padding(
            padding: const EdgeInsets.symmetric(vertical:8.0),

            /// 文档说,RepaintBoundary widget在渲染树的层中创建了一个RenderRepaintBoundary。这用于减少需要重绘的需求量。
            /// 我的理解是,RepaintBoundary会减少其children的重绘,可以提高性能
            child: RepaintBoundary(
              child: Column(上海海洋大学
                children: List < Widget>.generate(rowCount, (int rowIndex) {
                /// 计算每行列数
                /// 如果是最后一列,那么就是剩下的菜单数量比如11个项目,最后一行是第4行,rowIndex是3,
                ///  menus.length - columnCount * math.max(0, rowCount - 1)
                ///  = 11 - 3 * math.max(0,4-1) = 2
                ///  即最后一行为2列。
                final int columnCountForRow = rowIndex == rowCount - 1
                    ? menus.length - columnCount * math.max(0, rowCount - 1)
                    : columnCount;
                return Row(
                    children: List < Widget>.generate(columnCountForRow, (
                    int columnIndex) {
                  final int index = rowIndex * columnCount + columnIndex;
                  final BoxMenuItem menuItem = menus[index];
                  return SizedBox(
                    width: columnWidth,
                    height: rowHeight,
                    child: Card (
                      color: Colors.grey.shade300,
                      /// customer widget
                      child: LabelBelowIcon(
                        betweenHeight: 15.0,
                        icon: menuItem.icon,
                        label: menuItem.label,
                        iconColor: Colors.indigo.shade800,
                        isCircleEnabled: false,
                        onPressed: menuItem.onPressed,
                      ),
                    ),
                  );
                }),);
              }),
            ),),
          );
        }),
    );
  }
}

class BoxMenuItem{
  final String _label;
  final IconData _icon;
  final _onPressed;

  get label => _label;

  get icon => _icon;

  get onPressed => _onPressed;

  BoxMenuItem(this._label, this._icon, this._onPressed);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102