Flutter:使用持久的侧边栏导航

时间:2021-01-15 14:26:23

标签: flutter flutter-layout flutter-web

我正在创建一个看起来像仪表板的 Flutter Web 项目。它有一个侧面导航和一个显示不同屏幕的主体区域。

为了实现这一点,我使用 Expanded 将我的屏幕分为两部分并给它们一个 flex 值。 为了显示不同的屏幕,我使用了 IndexedStack。

这是我的 main.dart 文件:

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,
                    ),
                  ),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

这是其中一个屏幕(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,
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

侧边导航按其应有的方式工作,并且在导航停留在左侧时加载了不同的页面。 当我点击 CourseScreen 上的任何小部件时,我想打开另一个屏幕来替换 CourseScreen,但导航应该仍然存在。

我怎样才能做到这一点?

注意:我是 flutter 的新手,我编写的大部分代码都不完美,可能不是一个好方法。如果您能指出上述文件中的错误代码,我将不胜感激。

谢谢!!!

0 个答案:

没有答案