如何将数据从有状态类传递到另一个文件中存在的另一个有状态类?

时间:2019-01-12 16:36:41

标签: dart flutter

我无法传递在textformfields中填充并在下拉菜单中选择的数据。

我正在尝试使用Map函数传递字符串值,以便将来我也可以传递所有类型的值(例如int,bool,double等),但是它不起作用,因此我需要有人来检查。

main.dart

import 'package:flutter/material.dart';
import 'package:workoutapp/auth/auth.dart';
import 'package:workoutapp/auth/root_page.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';

void main(List<String> args) {
  runApp(
    WorkoutManager(),
  );
}

class WorkoutManager extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AuthProvider(
      auth: Auth(),
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Workout Manager',
        home: RootPage(),
        theme: ThemeData(
          primaryColor: Colors.indigo,
          primarySwatch: Colors.indigo,
          accentColor: Colors.indigoAccent,
          hintColor: Colors.indigo,
          brightness: Brightness.dark,
        ),
      ),
    );
  }
}

主页

import 'package:flutter/material.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';

import './profile_account_page.dart';
import './routines_create_page.dart';

import '../objects/Routines/routines_manager.dart';

import '../tools/custom_drawer.dart';

class HomePage extends StatelessWidget {
  final VoidCallback onSignedOut;
  final List<Map<String, String>> routines;

  HomePage({Key key, this.onSignedOut, this.routines}) : super(key: key);

  void _signedOut(BuildContext context) async {
    try {
      var auth = AuthProvider.of(context).auth;
      await auth.signOut();
      onSignedOut();
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Workout Manager', style: TextStyle(color: Colors.white)),
        centerTitle: false,
        actions: <Widget>[
          FlatButton(
            child: Text('Logout'),
            onPressed: () {
              return _signedOut(context);
            },
          ),
          IconButton(
            icon: Icon(Icons.account_box),
            tooltip: 'Profile Account',
            color: Colors.white,
            onPressed: () {
              return Navigator.push(context,
                  MaterialPageRoute(builder: (BuildContext context) {
                return ProfileAccountPage();
              }));
            },
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          Navigator.push(context,
              MaterialPageRoute(builder: (BuildContext context) {
            return RoutinesPageCreate();
          }));
        },
      ),
      body: RoutinesManager(),
      drawer: CustomDrawer(),
    );
  }
}

RoutineManager

import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines.dart';

class RoutinesManager extends StatefulWidget {
  final Map<String, String> startingRoutine;

  RoutinesManager({this.startingRoutine});

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

class _RoutinesManagerState extends State<RoutinesManager> {
  List<Map<String, String>> _routines = [];

  @override
  void initState() {
    if (widget.startingRoutine != null) {
      _routines.add(widget.startingRoutine);
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Expanded(
          child: Routines(_routines),
        )
      ],
    );
  }
}

RoutinesCreatePage

import 'package:flutter/material.dart';
import 'package:workoutapp/pages/home_page.dart';

class RoutinesPageCreate extends StatefulWidget {
  @override
  _RoutinesPageCreateState createState() => _RoutinesPageCreateState();
}

class _RoutinesPageCreateState extends State<RoutinesPageCreate> {
  final formKey = GlobalKey<FormState>();
  List<Map<String, String>> _routines = [];

  String _routineName, _routineDescription;

  var _routineNameController = TextEditingController();
  var _routineDescriptionController = TextEditingController();

  List<DropdownMenuItem<String>> _dropdownListBodyPartMenuItem = [];
  List<String> _dropdownListBodyPart = [
    'Chest',
    'Back',
    'Leg',
    'Shoulder',
    'Abs',
  ];
  String _selectedBodyPart;

  List<DropdownMenuItem<String>> _dropdownListDayOfWeekMenuItem = [];
  List<String> _dropdownListDayOfWeek = [
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday',
    'Sunday',
  ];
  String _selectedDayOfWeek;

  void loadBodyPartData() {
    _dropdownListBodyPartMenuItem = [];
    _dropdownListBodyPartMenuItem = _dropdownListBodyPart.map((val) {
      return DropdownMenuItem<String>(
        child: Text(val),
        value: val,
      );
    }).toList();
  }

  void loadDayOfWeekData() {
    _dropdownListDayOfWeekMenuItem = [];
    _dropdownListDayOfWeekMenuItem = _dropdownListDayOfWeek.map((val) {
      return DropdownMenuItem<String>(
        child: Text(val),
        value: val,
      );
    }).toList();
  }

  final _scaffoldState = GlobalKey<ScaffoldState>();

  void _showSnakBarReset() {
    _scaffoldState.currentState.showSnackBar(
      SnackBar(
        backgroundColor: Theme.of(context).accentColor,
        content: Text('Showing SnackBar TEST'),
      ),
    );
  }

  void _showSnakBarCreateWorkoutRoutine() {
    _scaffoldState.currentState.showSnackBar(
      SnackBar(
        backgroundColor: Theme.of(context).accentColor,
        content: Text('Workout Routine has been created'),
      ),
    );
  }

  void _addRoutine(Map<String, String> routine) {
    setState(() {
      _routines.add(routine);
    });
  }

  @override
  Widget build(BuildContext context) {
    loadBodyPartData();
    loadDayOfWeekData();
    return Scaffold(
      key: _scaffoldState,
      appBar: AppBar(
        title: Text('Create Routines'),
      ),
      body: Container(
        padding: EdgeInsets.all(15.0),
        child: Form(
          key: formKey,
          child: ListView(children: buildInputs() + buildCreateButtons()),
        ),
      ),
    );
  }

  List<Widget> buildInputs() {
    TextStyle textStyle = Theme.of(context).textTheme.title;
    return [
      TextFormField(
          controller: _routineNameController,
          validator: (value) {
            if (value.length > 20) {
              return 'Not a valid Routine Name';
            }
          },
          onSaved: (value) {
            return _routineName = value;
          },
          decoration: InputDecoration(
              labelStyle: textStyle,
              labelText: 'Routine Name',
              hintText: 'Enter the Routine Name for this day',
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(5.0),
              ))),
      Padding(padding: EdgeInsets.all(7.0)),
      TextFormField(
          controller: _routineDescriptionController,
          validator: (value) {
            if (value.length > 50) {
              return 'Invalid: The Description must be 50 characters or less.';
            }
          },
          onSaved: (value) {
            return _routineDescription = value;
          },
          decoration: InputDecoration(
              labelStyle: textStyle,
              labelText: 'Description',
              hintText: 'Enter the description of the Routine.',
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(5.0),
              ))),
      Padding(padding: const EdgeInsets.all(7.0)),
      Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          DropdownButtonHideUnderline(
              child: DropdownButton(
                  value: _selectedBodyPart,
                  items: _dropdownListBodyPartMenuItem,
                  hint: Text('Select Body Part', style: textStyle),
                  onChanged: (value) {
                    setState(() {
                      _selectedBodyPart = value;
                    });
                  })),
          Padding(
            padding: const EdgeInsets.all(1.0),
          ),
          DropdownButtonHideUnderline(
            child: DropdownButton(
              value: _selectedDayOfWeek,
              items: _dropdownListDayOfWeekMenuItem,
              hint: Text('Select Day of Week', style: textStyle),
              onChanged: (value) {
                setState(() {
                  _selectedDayOfWeek = value;
                });
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(4.0),
          )
        ],
      ),
    ];
  }

  List<Widget> buildCreateButtons() {
    return [
      Padding(
        padding: const EdgeInsets.all(5.0),
        child: Row(
          children: <Widget>[
            Expanded(
              child: RaisedButton(
                  textColor: Theme.of(context).primaryColorDark,
                  color: Theme.of(context).accentColor,
                  child: Text('Create Workout Routine'),
                  onPressed: () {
                    if (formKey.currentState.validate()) {
                      _showSnakBarCreateWorkoutRoutine();
                      formKey.currentState.save();
                      _addRoutine({
                        'routineName': 'Chest Workout',
                        'description': 'Heavy',
                        'bodyPart': 'Chest',
                        'week': 'Monday',
                      });
                      Navigator.push(context,
                          MaterialPageRoute(builder: (BuildContext context) {
                        return HomePage();
                      }));
                    } else {
                      return null;
                    }
                  }),
            ),
            Expanded(
              child: RaisedButton(
                textColor: Theme.of(context).primaryColorLight,
                color: Theme.of(context).primaryColorDark,
                child: Text('Reset'),
                onPressed: () {
                  setState(() {
                    _showSnakBarReset();
                    formKey.currentState.reset();
                    _selectedBodyPart = null;
                    _selectedDayOfWeek = null;
                  });
                },
              ),
            ),
          ],
        ),
      ),
    ];
  }
}

常规

import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines_detail.dart';

class Routines extends StatelessWidget {
  final List<Map<String, String>> routines;

  Routines(this.routines);

  Widget _buildRoutinesItem(BuildContext context, int index) {
    TextStyle textStyle = Theme.of(context).textTheme.title;
    return Expanded(
      child: Card(
        margin: EdgeInsets.all(5.0),
        child: Column(
          children: <Widget>[
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(routines[index]['routineName'], style: textStyle)),
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(routines[index]['description'], style: textStyle)),
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(routines[index]['bodyPart'], style: textStyle)),
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(routines[index]['week'], style: textStyle)),
            Padding(
              padding: const EdgeInsets.all(5.0),
              child: ButtonBar(
                alignment: MainAxisAlignment.center,
                children: <Widget>[
                  FlatButton(
                    child: Text('Details'),
                    onPressed: () {
                      return Navigator.push(context,
                          MaterialPageRoute(builder: (BuildContext context) {
                        return RoutinesDetail(
                            routines[index]['routineName'],
                            routines[index]['description'],
                            routines[index]['bodyPart'],
                            routines[index]['week']);
                      }));
                    },
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }

  Widget _buildRoutinesList(context) {
    TextStyle textStyle = Theme.of(context).textTheme.title;
    Widget routinesCards = Container(
      child: Container(
        child: Center(
          child: Text("No routines found, please add some.", style: textStyle),
        ),
      ),
    );
    if (routines.length > 0 || routines.length <= 7) {
      ListView.builder(
        itemBuilder: _buildRoutinesItem,
        itemCount: routines.length,
      );
    }
    return routinesCards;
  }

  @override
  Widget build(BuildContext context) {
    return _buildRoutinesList(context);
  }
}

RoutineDetailPage

import 'package:flutter/material.dart';

class RoutinesDetail extends StatelessWidget {
  final String routineName, description, bodyPart, week;

  RoutinesDetail(this.routineName, this.description, this.bodyPart, this.week);

  @override
  Widget build(BuildContext context) {
    TextStyle textStyle = Theme.of(context).textTheme.title;
    return Scaffold(
      appBar: AppBar(
        title: Text(routineName),
        centerTitle: true,
      ),
      body: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(routineName, style: textStyle)),
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(description, style: textStyle)),
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(bodyPart, style: textStyle)),
            Padding(
                padding: const EdgeInsets.all(5.0),
                child: Text(week, style: textStyle)),
            Container(
              padding: EdgeInsets.all(5.0),
              child: RaisedButton(
                child: Text('Delete'),
                onPressed: () {
                  Navigator.pop(context);
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

如您所见,我正在尝试将代码尽可能地分成多个文件,因此它更具“可读性”,并让我自己很容易在以后需要时对代码进行更改。 问题是,它非常难处理,我不知道如何使用数据并将其向下或向上传递到页面或小部件,因为应该有多个有状态和无状态的小部件一起工作才能使此应用成为可能。

您会在首页文件(StatelessWidget)上注意到,我正在尝试使用RoutinesManager StatefulWidget显示Scaffold主体参数,该文件位于另一个文件中。同时在HomePage文件中,我有一个Scaffold floatActionButton参数,它将带您进入RoutinesCreatePage StatefulWidget,以使用ListView.builder()创建卡列表(StatelessWidget)。但是,在RoutinesCreatePage中按下“创建锻炼程序” RaisedButton之后,不会在首页下创建卡。

由于我一无所知,有人可以在这里帮助我吗?另外,我还是关于颤振/飞镖的初学者,因此相对易于理解的解释解决方案将非常有帮助。

注意:我确实有其他与此应用程序有关的文件,但是我认为它们不是问题的一部分,因此我特意将它们排除在外。

如果需要更多信息,请告诉我。

谢谢!

1 个答案:

答案 0 :(得分:0)

您似乎误解了Flutter的状态。简而言之,状态是属于该特定小部件的内部状态/数据/...。 StatefulWidget的状态可以确定是否应根据自己的状态更改重新呈现UI。外部窗口小部件从不知道其他窗口小部件的状态。

因此,这意味着RoutinesCreatePage小部件内发生的任何状态更改,只有RoutinesCreatePage知道并做出反应。除非您通知其他小部件知道某些更改。

好的,所以谈到导航,它就像一个堆栈结构。 HomePage触发向RoutinesCreatePage的推送,然后要返回,则需要pop,而不是另一个push

这里是您的代码的快速修复方法,您可以尝试。

主页

floatingActionButton: FloatingActionButton(
    child: Icon(Icons.add),
    onPressed: () {
        handleNewRoutine();  <---  this is to handle navigation and retrieve returning data from pop
    },  
),

Future handleNewRoutine() async {

    var newRoutine = await Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => RoutinesPageCreate());
    )

    if (newRoutine == null) {
        // nothing returns from RoutinesPageCreate widget
        // so do nothing then
    } else {
        // add to routine list 
        // and trigger list re-rendering
        setState(() {
            this.routines.add(newRoutine); 
        });
    }
}

RoutinesCreatePage :单击提交按钮时,只需填充输入字段中的所有数据,制作对象模型,然后弹出以将数据返回到推送此小部件的位置。

onPressed: () {
    var newRoutine = .... // populate from UI to create new Routine model object.
    Navigator.pop(context, newRoutine);
}

此外,请花一些时间阅读Flutter官方文档中的导航指南。这部分非常详细。 https://flutter.io/docs/cookbook/navigation/returning-data

您的代码还有一些其他注释:

  • RoutinesCreatePage中,您不需要了解应用程序级别的状态,我的意思是_routines变量是不必要的。您只需要一个对象即可存储新例程,以弹出回到HomePage
  • Routines中,此方法Widget _buildRoutinesList(context)具有未使用的ListView创建。

    if (routines.length > 0 || routines.length <= 7) { ListView.builder( itemBuilder: _buildRoutinesItem, itemCount: routines.length, ); }