Flutter - Add a set of FloatingActionButtons with Flow to a NavigationRail

Viewed 24

Still learning Flutter and I'm wondering if it is possible to have a "fly-out" set of buttons in a NavigationRail?

The code base I'm starting to use is from the Flutter team here about the Flow class: https://api.flutter.dev/flutter/widgets/Flow-class.html

What I'm trying to do is add this to a NavigationRail. Below is the code I have for the Navigation rail and what I have so far for the Flow class with a single icon. The Error is at the bottom.

NavigationRail code:

        body: Column(
          children: <Widget>[
            Expanded(
              child: Row(
                children: [
                  Visibility(
                    visible: !showBottomNav,
                    child: Flexible(
                      flex: 1,
                      child: NavigationRail(
                          backgroundColor: kQptColorLightGrey200,
                          elevation: 4,
                          selectedIconTheme: const IconThemeData(
                            color: kQptColorPrimaryDarkTeal,
                          ),
                          selectedLabelTextStyle: const TextStyle(color: kQptColorPrimaryDarkTeal, fontSize: 14),
                          unselectedIconTheme: const IconThemeData(
                            color: kQptColorPrimaryDarkTeal,
                          ),
                          unselectedLabelTextStyle: const TextStyle(color: kQptColorPrimaryDarkTeal, fontSize: 14),
                          labelType: NavigationRailLabelType.all,
                          destinations: [
                            
                            NavigationRailDestination(
                              icon: Icon(
                                Icons.calendar_month,
                                size: 30,
                              ),
                              label: FittedBox(
                                child: Text("Scheduler"),
                              ),
                            ),
                            NavigationRailDestination(
                              icon: Icon(
                                Icons.add_circle,
                                size: 30,
                              ),
                              label: FittedBox(
                                child: Text(kQptBtnAddEventText),
                              ),
                            ),
                            NavigationRailDestination(
                              icon: LocationFlowWidget(),
                              label: FittedBox(
                                child: Text("Locations"),
                              ),
                            ),
                          ],
                          onDestinationSelected: (index) async {
                            setState(() {
                              currentNavIndex = index;
                            });
                            switch (currentNavIndex) {

                              case 0:
                                {
                                  /// PROFILE SCREEN
                                  Navigator.popAndPushNamed(context, CalendarScreen.id);
                                }
                                break;
                              case 1:
                                {
                                  ScaffoldMessengerState scaffoldState = ScaffoldMessenger.of(context);
                                 final submitStatus = await SchedulerUtils.openCreateDialog(context, "${targetUser.fname} ${targetUser.lname}");
                                  final scaffoldController = scaffoldState.showSnackBar(
                                    SnackBar(
                                      content: Text(submitStatus ?? "Closing the dialog..."),
                                    ),
                                  );
                                }
                                break;
                              default:
                                {
                                  /// TODO: filtering stuff based on location selected
                                  print("locations was selected");
                                }
                                break;
                            }
                          },
                          selectedIndex: null),
                    ),
                  ),
                  Flexible(
                    flex: 12,
                    child: Padding(
                      padding: const EdgeInsets.only(
                        top: 20.0,
                        bottom: 20.0,
                      ),
                      child: Column(
                        mainAxisSize: MainAxisSize.max,
                        children: [
                          const Text(                         
                            'Location Calendar',
                            style: TextStyle(fontSize: 28, color: Colors.blueGrey, fontWeight: FontWeight.bold),
                            textAlign: TextAlign.center,
                          ),
                          Expanded(
                            child: MyCalendar(
                              inputCurrentUser: targetUser,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),

Location flow class that uses the Flow object:


const double buttonSize = 30;

class LocationFlowWidget extends StatefulWidget {
  const LocationFlowWidget({Key? key}) : super(key: key);

  @override
  State<LocationFlowWidget> createState() => _LocationFlowWidgetState();
}

class _LocationFlowWidgetState extends State<LocationFlowWidget> {
  @override
  Widget build(BuildContext context) => Flow(
        delegate: MyFlowDelegate(),
        children: <IconData>[
          Icons.mail,
        ].map<Widget>(buildItem).toList(),
      );

  /// this converts the icons into Floating action buttons
  Widget buildItem(IconData icon) {
    return Expanded(
      child: SizedBox(
        width: buttonSize,
        height: buttonSize,
        child: FloatingActionButton(
          elevation: 0,
          splashColor: Colors.black,
          child: Icon(
            icon,
            color: Colors.white,
            size: 30,
          ),
          onPressed: () {
            /// do stuff
          },
        ),
      ),
    );
  }
}

class MyFlowDelegate extends FlowDelegate {
  @override
  void paintChildren(FlowPaintingContext context) {
    /// This will tell Flutter where to draw each of Flows children
    /// the i is the index within the list of children
    context.paintChild(
      0,
    );
  }

  @override
  bool shouldRepaint(covariant FlowDelegate oldDelegate) => false;
}

The error I'm getting is as follows: ======== Exception caught by widgets library ======================================================= The following assertion was thrown while applying parent data.: Incorrect use of ParentDataWidget.

The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject, which has been set up to accept ParentData of incompatible type ParentData.

Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically, Expanded widgets are placed directly inside Flex widgets. The offending Expanded is currently placed inside a RepaintBoundary widget.

The ownership chain for the RenderObject that received the incompatible parent data was: SizedBox ← Expanded ← RepaintBoundary-[<0>] ← Flow ← LocationFlowWidget ← IconTheme ← _AddIndicator ← Column ← Padding ← ConstrainedBox ← ⋯

0 Answers
Related