在Flutter Dart中访问和修改来自不同类的变量

时间:2020-04-03 09:58:51

标签: flutter dart flutter-layout

我有一个模型类,我曾经用它从一个主要的有状态类中创建一个对象。我的主班有一个文本框和一个按钮。但是他们都是完全不同的有状态阶级。也就是说,我在dart文件中有3个不同的类(主页,文本字段,按钮)。我想在我的文本字段和按钮中访问和修改在主页构建中启动的对象。

我所做的事情:假设所有类都可以访问它们,我已将我的对象放在dart文件中所有类的顶部。那是成功的。所有类都可以访问该对象,即使从主页面向该对象初始化的值也可以在其他类(文本字段,按钮)中使用。

我现在遇到的问题:尽管我可以访问对象中的那些值,但无论FancyTextField,我都无法将其修改为StatusButton类中的最新值类更新。

我的项目做什么::我将从firestore数据库的主页构建中获取一些值,并将其传递给其他两个类中的textfield和button。这样,它类似于我的值在上面。然后,我将从文本字段和按钮将修改后的值保存到对象,然后将其从主页上传到Firestore数据库。

页面的完整代码:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
import 'package:om/models/machine.dart';
import 'package:om/utils/kalaicons_icons.dart';

Machine machine;

class WorkshopTool extends StatefulWidget {
  final String rotary;

  WorkshopTool(this.rotary);

  @override
  _WorkshopToolState createState() => _WorkshopToolState(rotary);
}

class _WorkshopToolState extends State<WorkshopTool> {
  String rotary;
  bool _showOnScreen = true;

  _WorkshopToolState(this.rotary);

  @override
  Widget build(BuildContext context) {
    var screenSize = MediaQuery.of(context).size;

    return FutureBuilder(
        future: Firestore.instance
            .collection('productionrpt')
            .document(rotary)
            .get(),
        builder: (context, snapshot) {
          if (!snapshot.hasData)
            return Container(
                height: screenSize.height - 50.0,
                child: Center(
                  child: SizedBox(
                      height: 80.0,
                      width: 80.0,
                      child: CircularProgressIndicator(
                        valueColor:
                            AlwaysStoppedAnimation<Color>(Colors.green[600]),
                        strokeWidth: 15.0,
                      )),
                ));
          machine = Machine.fromMapObjext(snapshot.data);
          return Container(
            height: screenSize.height - 50.0,
            width: screenSize.width,
            child: Stack(
              children: <Widget>[
                SingleChildScrollView(
                  child: Column(
                    children: <Widget>[
                      //To make a empty column space for stack on top
                      Container(
                        height: 80.0,
                        padding: EdgeInsets.only(bottom: 5.0, right: 15.0),
                        child: Align(
                          alignment: Alignment.bottomRight,
                          child: Text(
                            machine.date,
                            style: TextStyle(
                                color: Colors.black,
                                fontSize: 17.0,
                                fontStyle: FontStyle.italic,
                                fontWeight: FontWeight.bold),
                          ),
                        ),
                      ),
                      FancyTextField('Production'),
                      FancyTextField('Damages'),
                      FancyTextField('Plan'),
                      SizedBox(
                        height: 20.0,
                      ),

                      Padding(
                          padding: EdgeInsets.only(
                              bottom:
                                  MediaQuery.of(context).viewInsets.bottom)),
                    ],
                  ),
                ),
                Container(
                  height: 50.0,
                  decoration: BoxDecoration(
                      color: Colors.green[400],
                      borderRadius:
                          BorderRadius.vertical(top: Radius.circular(15.0))),
                ),
                Align(
                  alignment: Alignment.bottomRight,
                  child: Padding(
                    padding: const EdgeInsets.all(20.0),
                    child: MaterialButton(
                        color: Colors.black,
                        padding: EdgeInsets.only(
                            top: 10.0, bottom: 10.0, left: 20.0, right: 20.0),
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(15.0)),
                        child: Text(
                          'UPDATE',
                          style: TextStyle(
                              fontSize: 30.0,
                              fontWeight: FontWeight.bold,
                              color: Colors.white),
                        ),
                        onPressed: () {
                          print('Saved to cloud : ${machine.production}');
                          firebasePutData();
                        }),
                  ),
                ),
                Align(
                  alignment: Alignment.bottomLeft,
                  child: Padding(
                    padding: EdgeInsets.all(20.0),
                    child: StatusButton(),
                  ),
                ),
                Align(
                  alignment: Alignment.topLeft,
                  child: IconButton(
                      icon: Icon(
                        Icons.close,
                        size: 40,
                        color: Colors.black,
                      ),
                      onPressed: () {
                        print('Bottomsheet closed');
                      }),
                ),
                Align(
                  alignment: Alignment.topCenter,
                  child: Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: Text(
                      machine.rotary,
                      style: TextStyle(
                          color: Colors.black,
                          fontSize: 20.0,
                          decoration: TextDecoration.underline,
                          fontWeight: FontWeight.bold),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(4.0),
                  child: Align(
                    alignment: Alignment.topRight,
                    child: Switch(
                        value: _showOnScreen,
                        activeTrackColor: Colors.black54,
                        activeColor: Colors.black,
                        inactiveThumbColor: Colors.grey[600],
                        inactiveTrackColor: Colors.grey[500],
                        onChanged: (v) {
                          _showOnScreen = !_showOnScreen;
                          print('Switch tapped');
                        }),
                  ),
                ),
              ],
            ),
          );
        });
  }

  void firebasePutData() {
    Firestore.instance
        .collection("productionrpt")
        .document(rotary)
        .updateData(machine.toMap());
    print('Data updated');
  }
} //End of main page STATE (a bottom sheet)

//#######################################################################################################
//############               FANCY TEXT FIELD FOR ENTERING MACHINE DATA                 #################

class FancyTextField extends StatefulWidget {
  final String _title;

  FancyTextField(
    this._title,
  );

  @override
  _FancyTextFieldState createState() => _FancyTextFieldState(this._title);
}

class _FancyTextFieldState extends State<FancyTextField> {
  final String _title;
  final TextEditingController _ctrl = TextEditingController();

  _FancyTextFieldState(this._title);

  @override
  void initState() {
    switch (_title) {
      case 'Production':
        _ctrl.text = machine.production.toString();
        break;
      case 'Plan':
        _ctrl.text = machine.plan.toString();
        break;
      case 'Damages':
        _ctrl.text = machine.damage.toString();
        break;
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 125.0,
      margin: EdgeInsets.all(8.0),
      decoration: BoxDecoration(
        color: Colors.green[400],
        borderRadius: BorderRadius.circular(15.0),
//                      boxShadow: [
//                        BoxShadow(
//                            blurRadius: 5, color: Colors.green[300], spreadRadius: 5)
//                      ]
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            _title,
            style: TextStyle(
                color: Colors.black,
                fontSize: 23.0,
                fontWeight: FontWeight.bold),
          ),
          Container(
            height: 50,
            width: 300,
            alignment: Alignment.center,
            padding: const EdgeInsets.all(5.0),
            margin: const EdgeInsets.only(
                top: 10.0, bottom: 10, left: 30.0, right: 30.0),
            decoration: BoxDecoration(
              color: Colors.white70,
              borderRadius: BorderRadius.circular(10),
            ),
            child: TextField(
              //maxLength: 5,
              controller: _ctrl,
              textAlign: TextAlign.center,
              keyboardType: TextInputType.number,
              style: TextStyle(
                color: Colors.black,
                fontSize: 30.0,
              ),
              decoration: InputDecoration(
                border: InputBorder.none,
              ),
              onChanged: (v) {
                switch (_title) {
                  case 'Production':
                    machine.production = int.parse(_ctrl.text);
                    break;
                  case 'Plan':
                    machine.plan = int.parse(_ctrl.text);
                    break;
                  case 'Damages':
                    machine.damage = int.parse(_ctrl.text);
                    break;
                }
                print('Prod: ${machine.production}');
              },
            ),
          ),
        ],
      ),
    );
  }
} //END OF CLASS FANCY TEXT FIELD

//######################################################################################################
//#######         A STATEFUL WIDGET FOR MACHINE STATUS BUTTON : running, off, breakdown       ##########

class StatusButton extends StatefulWidget {
  @override
  _StatusButtonState createState() => _StatusButtonState();
}

class _StatusButtonState extends State<StatusButton> {
  Color color;
  IconData icon;

  @override
  Widget build(BuildContext context) {
    switch (machine.stats) {
      case 0:
        color = Colors.grey[600];
        icon = Icons.power_settings_new;
        break;
      case 1:
        color = Colors.blue;
        icon = Icons.power_settings_new;
        break;
      default:
        color = Colors.red;
        icon = Kalaicons.breakdown;
        break;
    }

    return Container(
        height: 70.0,
        width: 70.0,
        decoration: BoxDecoration(
          color: color,
          shape: BoxShape.circle,
        ),
        child: IconButton(
          icon: Icon(
            icon,
            color: Colors.white,
            size: 50.0,
          ),
          onPressed: () {
            setState(() {
              machine.stats > 1 ? machine.stats = 0 : machine.stats++;
              print('Status button pressed:  ${machine.stats}');
            });
          },
        ));
  }
} //END OF CLASS STATUS BUTTON


我的模型:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';

class Machine {
  int _production;
  int _plan;
  int _damage;
  int _stats = 0;
  String _date = '~Not available';
  String _rotary;

//  Machine(this._production, this._damage, this._date,
//      [this._stats, this._plan]);

  int get production => this._production;

  int get plan => this._plan;

  int get damage => this._damage;

  int get stats => this._stats;

  String get date => this._date;

  String get rotary => this._rotary;

  set production(int updatedValue) {
    if (updatedValue != null) {
      this._production = updatedValue;
    }
  }

  set plan(int updatedValue) {
    if (updatedValue != null) {
      this._plan = updatedValue;
    }
  }

  set damage(int updatedValue) {
    if (updatedValue != null) {
      this._damage = updatedValue;
    }
  }

  set stats(int updatedValue) {
    this._stats = updatedValue;
  }

//  set date(String updatedValue) {
//    this._date = DateFormat.jm().format(DateTime.now());
//
//  }

//Function to set a map list of new data for firebase
  Map<String, dynamic> toMap() {
    var map = Map<String, dynamic>();
    map['production'] = this._production;
    map['plan'] = this._plan;
    map['damages'] = this._damage;
    map['stats'] = this._stats;
    map['date'] = DateFormat("MMMM dd, hh:mm a").format(DateTime.now());
    return map;
  }

//Constructor to extract firebase collections
  Machine.fromMapObjext(DocumentSnapshot map) {
    this._production = map['production'];
    this._plan = map['plan'];
    this._damage = map['damages'];
    this._stats = map['stats'];
    this._date = map['date'];
    this._rotary = map['machine'];
  }
}

My app looks like this

最近更新: StatusButton的值已被gettiong更新为对象和Firestore。但是更新后的FancyTextField的值仅反映在该类本身内部。不全局更新。

1 个答案:

答案 0 :(得分:1)

最后,我自己发现问题持续了3天。发生问题是因为弹出键盘时,小部件还可以重新构建状态。由于我的Firebase数据存储在构建中的FutureBuilder上,因此我的旧数据再次从Firebase撤回,并将其保存在新编辑的数据之上。

为什么我放在TextField上的初始文本没有更改? 因为我已将其设置在initState类的FancyTextField上,所以在重建小部件时,我将不会执行,并且编辑后的值将保持不变。

为什么要更新StatusButton值而不失败? 因为当我点击按钮键盘时,不会弹出,并且构建也不会重新构建。但是后来我注意到,在将StatusButton状态更改为其他值并点击TextField使其变为OLD值(即当前在Firebase中的值)之后,我注意到了。由于构建是重新创建的。我就是这么想的。

我为克服此问题所做的工作: 我只是删除了从Firebase获取数据的FutureBuilder,并为其创建了一个Future,并在initState中对其进行了初始化。

如果有人愿意,我可以在此处显示更新的代码