简体   繁体   English

在 state 更改 flutter 后 UI 不更新

[英]UI does not update after state change flutter

I am building a flutter app that includes a form.我正在构建一个包含表单的 flutter 应用程序。 The form implements the bottom sheet modal which I implemented using a flat button where the child is a text and it changes dynamically when the user selects a value in the bottom sheet modal.该表单实现了底部表单模式,我使用一个平面按钮实现了该表单,其中子元素是文本,并且当用户在底部表单模式中选择一个值时它会动态变化。 Everything works fine but UI does not update when the state changes that is the text child of the flat button do not change.一切正常,但当 state 更改时 UI 不会更新,即平面按钮的文本子项不会更改。 Below is the code.下面是代码。 I am also open to suggestions on how I can use text form input to implement bottom sheet modal.我也愿意接受有关如何使用文本表单输入来实现底部表单模式的建议。

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shelter/models/user.dart';
import 'package:shelter/src/screens/home.screen.dart';
import 'package:shelter/src/screens/verification.screen.dart';
import 'package:shelter/src/utils/sizeconfig.dart';

class SignupScreen extends StatefulWidget {
  @override
  _SignupScreenState createState() => _SignupScreenState();
}

class _SignupScreenState extends State<SignupScreen> {
  GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final _user = User();

  String _selectedAge;
  String _selectedGender;
  String _selectedRegion;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _selectedAge = 'Select your age group';
    _selectedGender = 'Select one..';
    _selectedRegion = 'Choose your locality..';
  }

  @override
  Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Scaffold(
      backgroundColor: Color(0xFFF7CEB7),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Padding(
              padding: EdgeInsets.symmetric(
                horizontal: 15.0,
                vertical: 25.0,
              ),
              child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Row(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: <Widget>[
                        IconButton(
                          onPressed: () => Navigator.pop(context),
                          icon: Icon(Icons.arrow_back_ios),
                          color: Color(0xFF2C4F68),
                          iconSize: 20.0,
                        ),
                      ],
                    ),
                    FlatButton(
                      onPressed: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => HomeScreen(),
                          ),
                        );
                        setState(() => _user.isAnonymous = true);
                      },
                      child: Text(
                        'Skip',
                        style: GoogleFonts.openSans(
                          color: Color(0xFF2C4F68),
                          fontSize: 16.0,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    )
                  ]),
            ),
            Container(
              height: SizeConfig.safeBlockVertical * 120,
              width: double.infinity,
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(20.0),
                  topRight: Radius.circular(20.0),
                ),
              ),
              child: Padding(
                padding: EdgeInsets.symmetric(
                  horizontal: 40.0,
                  vertical: 20.0,
                ),
                child: Form(
                  key: _formKey,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Text(
                        'Create account',
                        style: GoogleFonts.openSans(
                          color: Color(0xFF2C4F68),
                          fontSize: 20.0,
                          fontWeight: FontWeight.w800,
                        ),
                      ),
                      SizedBox(
                        height: 10.0,
                      ),
                      Text(
                        'Please enter your details',
                        style: GoogleFonts.openSans(
                          color: Color(0xFF2C4F68),
                          fontSize: 16.0,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      SizedBox(
                        height: SizeConfig.safeBlockVertical * 2,
                      ),
                      TextFormField(
                        decoration: InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: 'Name',
                        ),
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'Please enter your full name';
                          }
                          return null;
                        },
                      ),
                      SizedBox(
                        height: SizeConfig.safeBlockVertical * 2,
                      ),
                      Text(
                        'Age Group',
                        style: GoogleFonts.openSans(
                          color: Color(0xFF2C4F68),
                          fontSize: 12.0,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      SizedBox(height: 5.0),
                      OutlineButton(
                        onPressed: () => _bringBottomSheet(300.0,
                            singleChildScrollView(_ageGroups, _selectedAge)),
                        borderSide: BorderSide(
                          color: Colors.grey,
                        ),
                        padding: EdgeInsets.only(
                            top: 20.0, bottom: 20.0, left: 10.0, right: 10.0),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(5.0),
                        ),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          mainAxisSize: MainAxisSize.max,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Text(
                              '$_selectedAge',
                              style: GoogleFonts.openSans(),
                            ),
                            Icon(
                              Icons.arrow_drop_down,
                            ),
                          ],
                        ),
                      ),
                      SizedBox(
                        height: SizeConfig.safeBlockVertical * 2,
                      ),
                      Text(
                        'Gender',
                        style: GoogleFonts.openSans(
                          color: Color(0xFF2C4F68),
                          fontSize: 12.0,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      SizedBox(height: 5.0),
                      OutlineButton(
                        onPressed: () => _bringBottomSheet(
                            200.0, _column(_gender, _selectedGender)),
                        borderSide: BorderSide(
                          color: Colors.grey,
                        ),
                        padding: EdgeInsets.only(
                            top: 20.0, bottom: 20.0, left: 10.0, right: 10.0),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(5.0),
                        ),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          mainAxisSize: MainAxisSize.max,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Text(
                              '$_selectedGender',
                              style: GoogleFonts.openSans(),
                            ),
                            Icon(
                              Icons.arrow_drop_down,
                            ),
                          ],
                        ),
                      ),
                      SizedBox(
                        height: SizeConfig.safeBlockVertical * 2,
                      ),
                      Text(
                        'Locality',
                        style: GoogleFonts.openSans(
                          color: Color(0xFF2C4F68),
                          fontSize: 12.0,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      SizedBox(height: 5.0),
                      OutlineButton(
                        onPressed: () => _bringBottomSheet(300.0,
                            singleChildScrollView(_regions, _selectedRegion)),
                        borderSide: BorderSide(
                          color: Colors.grey,
                        ),
                        padding: EdgeInsets.only(
                            top: 20.0, bottom: 20.0, left: 10.0, right: 10.0),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(5.0),
                        ),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          mainAxisSize: MainAxisSize.max,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Text(
                              '$_selectedRegion',
                              style: GoogleFonts.openSans(),
                            ),
                            Icon(
                              Icons.arrow_drop_down,
                            ),
                          ],
                        ),
                      ),
                      SizedBox(
                        height: SizeConfig.safeBlockVertical * 2,
                      ),
                      TextFormField(
                        decoration: InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: 'Household size',
                        ),
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'Please enter your full name';
                          }
                          return null;
                        },
                      ),
                      SizedBox(
                        height: SizeConfig.safeBlockVertical * 3,
                      ),
                      Center(
                        child: FlatButton(
                          color: Color(0xFF2C4F68),
                          textColor: Colors.white,
                          padding: EdgeInsets.all(15.0),
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          onPressed: () {
                            Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (context) => HomeScreen(),
                              ),
                            );
                          },
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            mainAxisSize: MainAxisSize.max,
                            children: <Widget>[
                              Text(
                                'Continue',
                                style: GoogleFonts.openSans(
                                  fontSize: 16.0,
                                  fontWeight: FontWeight.w600,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }

  List<String> _ageGroups = [
    '0 - 10',
    '11 - 20',
    '21 - 30',
    '31 - 40',
    '41 - 50',
    '51 - 60',
    '61 - 70',
    '71 - 80',
    '81 - 90',
    'over 90'
  ];

  List<String> _regions = [
    'Ashanti',
    'Greater Accra',
    'Central',
    'Volta',
    'Eastern',
    'Northern',
  ];

  List<String> _gender = [
    'Male',
    'Female',
    'Prefer not to say',
  ];

  void _bringBottomSheet(double height, childWidget) {
    showModalBottomSheet(
        context: context,
        builder: (context) {
          return StatefulBuilder(
            return Container(
              color: Color(0xFF737373),
              height: height,
              child: Container(
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(10.0),
                    topRight: Radius.circular(10.0),
                  ),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(15.0),
                  child: childWidget,
                ),
              ),
            );
        });
  }

  SingleChildScrollView singleChildScrollView(
      List dataList, String setVariable) {
    return SingleChildScrollView(child: _column(dataList, setVariable));
  }

  Column _column(List mapElement, String varTobeSet) {
    return Column(
      children: mapElement
          .map(
            (value) => ListTile(
              title: Text(
                value,
                style: GoogleFonts.openSans(
                  color: Color(0xFF2C4F68),
                ),
              ),
              onTap: () => _selectItem(value, varTobeSet),
            ),
          )
          .toList(),
    );
  }

  void _selectItem(String value, String stateVariable) {
    print(stateVariable);
    Navigator.pop(context);
    setState(() {
      stateVariable = value;
      print(stateVariable);
    });
  }
}

The issue is that the context is different.问题是上下文不同。 After you execute "Navigator.pop(context)" in "_selectItem," you should return the value that you want to set in the parent widget.在“_selectItem”中执行“Navigator.pop(context)”后,您应该返回要在父窗口小部件中设置的值。

If you take a look at the documentation of showModalBottomSheet method , you find that the method is a Future that returns the value in Navigator.pop.如果您查看showModalBottomSheet 方法的文档,您会发现该方法是一个 Future,它返回 Navigator.pop 中的值。

Returns a Future that resolves to the value (if any) that was passed to Navigator.pop when the modal bottom sheet was closed.返回一个 Future,它解析为关闭模式底部工作表时传递给 Navigator.pop 的值(如果有)。

So you will want to return the value with the Navigator.pop(context, value) function and set the state after the Future is resolved in the parent widget.因此,您需要使用 Navigator.pop(context, value) function 返回值,并在父窗口小部件中解析未来后设置 state。

[...]
void _bringBottomSheet(double height, childWidget) {
  var value = await showModalBottomSheet(...)
  setState((){stateVariable = value;})
  [...]

Additionally, I would double-check the showModalBottomSheet method in your solution.此外,我会仔细检查您的解决方案中的 showModalBottomSheet 方法。 You should remove the StateBuilder inside of the bottomModalSheet.您应该删除bottomModalSheet 内的StateBuilder。

This should be fairly simple, just put the showModalBottomSheet on the onTap callback of the TextFormField.这应该相当简单,只需将 showModalBottomSheet 放在 TextFormField 的 onTap 回调中即可。

  TextFormField(
    decoration: InputDecoration(
      border: OutlineInputBorder(),
      labelText: 'Name',
    ),
    onTap: () {
      var value = showModalBottomSheet(
          context: context,
          builder: (context) => Container());
      // DO something with the value for example update a TextEditingController or your state
    },
    validator: (value) {
      if (value.isEmpty) {
        return 'Please enter your full name';
      }
      return null;
    },
  ),

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM