Flutter : Navigate with persistent side bar

0

I'm creating a flutter web project that looks like a dashboard. It has a side navigation and a body area that displays different screens.

To achieve this, I have divided my screen into two parts using Expanded and given them a flex value. And to display different screens I have used IndexedStack.

Here is my main.dart file :

import 'package:flutter/material.dart';
import 'package:xxx/screens/courses/courses_screen.dart';
import 'package:xxx/side_navigation/menu_item.dart';
import 'package:xxx/componnents/header.dart';
import 'package:websafe_svg/websafe_svg.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        visualDensity: VisualDensity.adaptivePlatformDensity,
        scaffoldBackgroundColor: Color(0xfffafafa),
        fontFamily: 'Poppins',
      ),
      home: MainScreenLayout(),
    );
  }
}

class MainScreenLayout extends StatefulWidget {
  @override
  _MainScreenLayoutState createState() => _MainScreenLayoutState();
}

class _MainScreenLayoutState extends State<MainScreenLayout> {
  int selectedIndex = 0;
  int hoverIndex = -1;
  Color bgColor = Colors.transparent;

  final List<MenuItem> menus = <MenuItem>[
    MenuItem(label: 'Home', icon: Icons.home, screen: Container()),
    MenuItem(label: 'Courses', icon: Icons.add, screen: Container()),
    MenuItem(label: 'Students', icon: Icons.face_outlined, screen: Container()),
    MenuItem(label: 'Home', icon: Icons.home, screen: Container()),
    MenuItem(label: 'Courses', icon: Icons.add, screen: Container()),
    MenuItem(label: 'Students', icon: Icons.face_outlined, screen: Container()),
  ];

  final List<Widget> _screens = [
    Container(
      child: Image.asset(
        'assets/try.png',
        width: 100,
        height: 100,
      ),
    ),
    CoursesScreen(),
    Container(
      child: WebsafeSvg.asset('assets/folder_icon.svg'),
    ),
  ];

  void _changeBg(int index) {
    setState(() {
      hoverIndex = index;
    });
  }

  void _resetBg() {
    setState(() {
      hoverIndex = -1;
    });
  }

  @override
  Widget build(BuildContext context) {
    double _width = MediaQuery.of(context).size.width;

    return Scaffold(
      body: Row(
        children: [
          Expanded(
            flex: 2,
            child: Container(
              decoration: BoxDecoration(
                color: Color(0xffffffff),
                borderRadius: BorderRadius.only(
                  topRight: Radius.circular(_width * 0.03),
                  bottomRight: Radius.circular(_width * 0.03),
                ),
              ),
              child: Column(
                children: <Widget>[
                  SizedBox(
                    height: 50,
                  ),
                  Flexible(
                    child: ListView.builder(
                      itemCount: menus.length,
                      itemBuilder: (BuildContext context, int index) {
                        return MouseRegion(
                          onHover: (event) {
                            _changeBg(index);
                          },
                          onExit: (event) {
                            _resetBg();
                          },
                          child: MenuItemLayout(
                            bgColor: hoverIndex == index
                                ? Color(0xfffafafa)
                                : Colors.transparent,
                            menuItem: menus[index],
                            isSelected: selectedIndex == index ? true : false,
                            onTap: () {
                              setState(() {
                                selectedIndex = index;
                              });
                            },
                          ),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ),
          ),
          Expanded(
            flex: 7,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Header(
                  label: menus[selectedIndex].label,
                ),
                Expanded(
                  child: Container(
                    child: IndexedStack(
                      index: selectedIndex,
                      children: _screens,
                    ),
                  ),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

Here is the code for one of the screens (CourseScreen)

import 'package:flutter/material.dart';
import 'package:vjti_dashboard/componnents/responsive.dart';
import 'package:vjti_dashboard/screens/courses/courses_card.dart';
import 'package:vjti_dashboard/screens/courses/courses_model.dart';

class CoursesScreen extends StatelessWidget {
  final List<CoursesModel> allCourses = [
    CoursesModel(courseId: '123', courseName: 'Ecommerce'),
    CoursesModel(courseId: '123', courseName: 'Big Data Analytics'),
    CoursesModel(courseId: '123', courseName: 'User Experience Design'),
    CoursesModel(courseId: '123', courseName: 'Technical Seminar'),
    CoursesModel(courseId: '123', courseName: 'Elective 1'),
  ];

  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.vertical,
      shrinkWrap: true,
      children: [
        Sample(
          headingLabel: 'First Year',
          allCourses: allCourses,
          courseColor: Color(0xffEEF1E6),
        ),
        Sample(
          headingLabel: 'Second Year',
          allCourses: allCourses,
          courseColor: Color(0xffF9F1D6),
        ),
        Sample(
          headingLabel: 'Third Year',
          allCourses: allCourses,
          courseColor: Color(0xffE2F0CB),
        ),
      ],
    );
  }
}

class Sample extends StatelessWidget {
  final String headingLabel;
  final Color courseColor;
  final List<CoursesModel> allCourses;

  const Sample({Key key, this.allCourses, this.headingLabel, this.courseColor})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          GestureDetector(
            onTap: () {},
            child: Container(
              padding: EdgeInsets.all(16),
              decoration: BoxDecoration(
                border: Border(
                  bottom: BorderSide(
                    color: Color(0xffd6d6d6),
                    width: 1.0,
                  ),
                ),
              ),
              child: Text(headingLabel),
            ),
          ),
          GridView.count(
            primary: false,
            physics: ScrollPhysics(), // to disable GridView's scrolling
            shrinkWrap: true,
            padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 0),
            crossAxisSpacing: 20,
            childAspectRatio: 3 / 1,
            mainAxisSpacing: 20,
            crossAxisCount: Responsive.isDesktop(context)
                ? 4
                : Responsive.isTablet(context)
                    ? 3
                    : 2,
            children: List.generate(
              allCourses.length,
              (index) {
                return CourseCard(
                  coursesModel: allCourses[index],
                  containerColor: courseColor,
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

The side navigation works as it should and different pages are loaded while the navigation sticks to the left. When I click on any widget on the CourseScreen, I want to open another screen that would replace CourseScreen but the navigation should still be there.

How can I achieve this?

Note : I'm new to flutter and most of the code that I have written is not perfect and probably is not a good way. I would appreciate if you can point out bad codes in the above files.

Thank You!!!

flutter
flutter-layout
flutter-web
asked on Stack Overflow Jan 15, 2021 by Akshat Yadav

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0