0

应用程序的功能

它在底部导航栏中有两个项目,在第一部分(课程)中,用户可以添加课程列表,每次添加新课程时,它将更新他们的整体 GPA 和最高平均水平。另一个是简单的“我需要在决赛中获得什么才能通过”部分(决赛预测器)。

以下是屏幕顶部的代码,显示了用户的整体 gpa、课程数量和最高平均值

import 'package:flutter/material.dart';
import 'package:gradecalculator/models/course.dart';

class TopDisplay extends StatefulWidget {
  final List<Course> courses;
  final maxAverage;
  final overallGPA;


  TopDisplay(this.courses, this.maxAverage, this.overallGPA);

  @override
  _TopDisplayState createState() => _TopDisplayState();
}

class _TopDisplayState extends State<TopDisplay> {
  @override
  Widget build(BuildContext context) {
    final mediaQuery = MediaQuery.of(context);
    return Card(
      margin: EdgeInsets.all(10),
      elevation: 5,
      color: Colors.grey[400],
      child:Row(
        children: <Widget> [
          Container(
            margin: EdgeInsets.all(10),
            child: CircleAvatar(
              child: widget.courses.isEmpty ? Text(
                "0.0",
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 25,
                ),
              )
                  :  Text(
                "${widget.overallGPA.toStringAsFixed(2)}",
                style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                    fontSize: 25
                ),
              ),
              radius: 45,
              backgroundColor: Colors.red,
            ),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              SizedBox(
                height: mediaQuery.size.height * 0.07,
              ),
              Row(
                children:<Widget> [
                  const Text(
                    'Number of Courses: ',
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 16,
                        fontWeight: FontWeight.bold
                    ),
                  ),
                  Text(
                    '${widget.courses.length}',
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 16
                    ),
                  ),
                ],
              ),
              Row(
                  children: <Widget>[
                    const Text(
                      'Highest Average:  ',
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 16,
                          fontWeight: FontWeight.bold
                      ),
                    ),
                    widget.courses.isEmpty ? Text(
                      '0.0',
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 16
                      ),
                    )
                        :
                    Text(
                      '${widget.maxAverage}%',
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 16
                      ),
                    )
                  ]
              ),
            ],
          ),
        ],
      ),
    );
  }
}

问题

如果我添加课程,一切都会正常工作,并且将显示需要显示的所有内容。如果我导航到决赛预测器,然后返回课程,课程列表仍会显示,但总体 GPA 和最高平均数会回到 0.0。

带有底部导航栏的选项卡屏幕的代码

import 'package:flutter/material.dart';

import 'predictions_screens.dart';
import '../models/course.dart';
import 'home_page.dart';

class TabsScreen extends StatefulWidget {
  final List<Course> listedCourses;


  TabsScreen(this.listedCourses);

  @override
  _TabsScreenState createState() => _TabsScreenState();
}

class _TabsScreenState extends State<TabsScreen> {
  final List<Map<String, Object>> _pages = [
    {'page': HomePage(), 'title': 'Courses'},
    {'page': PredictionsScreen(), 'title': 'Final Grade Calculator'}
  ];

  int _selectedPageIndex = 0;

  void _selectPage(int index) {
      setState(() {
        _selectedPageIndex = index;

      });

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text(_pages[_selectedPageIndex]['title']),
      ),
      body: _pages[_selectedPageIndex]['page'],
      bottomNavigationBar: BottomNavigationBar(
        onTap: _selectPage,
        backgroundColor: Theme.of(context).primaryColor,
        unselectedItemColor: Colors.white,
        selectedItemColor: Theme.of(context).accentColor,
        currentIndex: _selectedPageIndex,
        items: [
          BottomNavigationBarItem(
              backgroundColor: Theme.of(context).primaryColor,
              icon: Icon(Icons.book),
              title: Text('Courses')),
          BottomNavigationBarItem(
              backgroundColor: Theme.of(context).primaryColor,
              icon: Icon(Icons.scatter_plot),
              title: Text('Finals Predictor'))
        ],
      ),
    );
  }
}

main.dart 文件中的代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'screens/predictions_screens.dart';
import 'screens/tabs_screen.dart';
import './models/course.dart';
import './screens/home_page.dart';

void main() {
  //To ensure that the app only is used in portrait mode
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
  runApp(GradeCalculator());
}

class GradeCalculator extends StatefulWidget {
  @override
  _GradeCalculatorState createState() => _GradeCalculatorState();
}

class _GradeCalculatorState extends State<GradeCalculator> {
  List<Course> coursesOnScreen = [];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Grade Calculator",
      theme: ThemeData(
        primarySwatch: Colors.red,
        accentColor: Colors.blueAccent[200],
      ),
     //home: HomePage(),
      routes: {
        '/': (ctx) => TabsScreen(coursesOnScreen),
        HomePage.routeName: (ctx) => HomePage(),
        PredictionsScreen.routeName: (ctx) => PredictionsScreen()
      },
    );
  }
}

课程列表输出代码

import 'package:flutter/material.dart';
import 'package:gradecalculator/models/course.dart';

class CourseList extends StatelessWidget {
  static const routeName = '/course-list';

  final List<Course> courses;
  final Function deletec;
  final Function setHighestAverage;
  final Function calculateGPA;

  CourseList(this.courses, this.deletec, this.setHighestAverage, this.calculateGPA);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: courses.length,
        itemBuilder: (ctx, index){
          return Card(
            elevation: 5,
            margin: EdgeInsets.symmetric(
              vertical: 5,
              horizontal: 8,
            ),
            child: ListTile(
              leading: CircleAvatar(
                radius: 20,
                child: Padding(
                  padding: EdgeInsets.all(6),
                  child: FittedBox(
                    child: Text(
                        '${courses[index].courseAverage}'
                    ),
                  ),
                ),
              ),
              title: Text(
                courses[index].courseName,
                style: TextStyle(
                    fontWeight: FontWeight.bold
                ),
              ),
              subtitle: Text(
                  'Course Weight: ${courses[index].courseWeight}'
              ),
              trailing: IconButton(
                icon: Icon(
                  Icons.delete,
                  color: Colors.grey,
                ),
                onPressed: () {
                  deletec(courses[index].courseName);
                  setHighestAverage(courses);
                  calculateGPA(courses);
                },
              ),
            ),
          );
        }
    );
  }
}

调用 TopDisplay 的主页文件

import 'package:flutter/material.dart';

import '../models/course.dart';
import '../widgets/newCourse.dart';
import '../widgets/course_list.dart';
import '../widgets/top_display.dart';

class HomePage extends StatefulWidget {
  static const routeName = '/home-page';
  final List<Course> visibleCourses = [];

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double maxAverage = 0.00;
  double overallGPA = 0.00;
  //List for courses as users add courses, this is where they will be stored


  //Calculates the total GPA shown in the top chart
  void calculateGPA(List<Course> courseList) {
    double totalWeight = 0;
    double intermediateGPA = 0;
    for (int i = 0; i < courseList.length; i++) {
      totalWeight += courseList[i].courseWeight;
      intermediateGPA +=
      (courseList[i].courseAverage * courseList[i].courseWeight);
      overallGPA = (intermediateGPA / totalWeight);
    }
  }

  //Finds the highest average that is displayed in the top chart
  void setHighestAverage(List<Course> courseList) {
    calculateGPA(courseList);
    for (int i = 0; i < courseList.length; i++) {
      if (courseList[i].courseAverage >= maxAverage) {
        maxAverage = courseList[i].courseAverage;
      }
    }
  }

  //Opens up the modal sheet that the user can use to enter a new course
  void _startAddNewCourse(BuildContext ctx) {
    showModalBottomSheet(
      context: ctx,
      builder: (_) {
        return GestureDetector(
          onTap: () {},
          behavior: HitTestBehavior.opaque,
          child: NewCourse(_addNewCourse),
        );
      },
    );
  }

  //Initializes the new course and adds it to the courses list above
  void _addNewCourse(String cTitle, double cAverage, double cWeight) {
    final newc = Course(
      courseName: cTitle,
      courseAverage: cAverage,
      courseWeight: cWeight,
    );
    setState(() {
      widget.visibleCourses.add(newc);
      setHighestAverage(widget.visibleCourses);
    });
  }

  void _deleteCourse(String courseName) {
    setState(() {
      widget.visibleCourses.removeWhere((c) {
        return c.courseName == courseName;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    //Setting up a mediaquery variable so that sizes can be determined based on phone size
    final mediaQuery = MediaQuery.of(context);
    return SafeArea(
      child: Scaffold(
        body: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              TopDisplay(widget.visibleCourses, maxAverage, overallGPA),
              Container(
                height: mediaQuery.size.height * 0.7,
                child: CourseList(
                    widget.visibleCourses, _deleteCourse, setHighestAverage, calculateGPA),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => _startAddNewCourse(context),
          backgroundColor: Colors.red,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}
4

0 回答 0