状态更改颤动后,UI不会更新

时间:2020-05-01 02:06:51

标签: flutter dart

我正在构建一个包含表单的Flutter应用程序。该表单实现了底层表单模式,我使用一个平面按钮(其中的孩子是文本)实现了该表单模式,当用户在底层表单模式中选择一个值时,它会动态变化。一切正常,但当状态更改(即平面按钮的文本子项未更改)时,UI不会更新。下面是代码。我也愿意就如何使用文本表单输入来实现底部表格模式提出建议。

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

1 个答案:

答案 0 :(得分:0)

问题在于上下文是不同的。在“ _selectItem”中执行“ Navigator.pop(context)”后,应返回要在父窗口小部件中设置的值。

如果您查看showModalBottomSheet method的文档,就会发现该方法是Future方法,该方法返回Navigator.pop中的值。

返回一个Future,该Future解析为模式底部关闭时传递给Navigator.pop的值(如果有)。

因此,您将要使用Navigator.pop(context,value)函数返回值,并在父窗口小部件中的Future解析后设置状态。

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

此外,我将在您的解决方案中再次检查showModalBottomSheet方法。您应该在bottomModalSheet内部删除StateBuilder。

这应该非常简单,只需将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;
    },
  ),