简体   繁体   中英

UI does not update after state change flutter

I am building a flutter app that includes a form. 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. 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.

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.

Returns a Future that resolves to the value (if any) that was passed to Navigator.pop when the modal bottom sheet was closed.

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.

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

Additionally, I would double-check the showModalBottomSheet method in your solution. You should remove the StateBuilder inside of the bottomModalSheet.

This should be fairly simple, just put the showModalBottomSheet on the onTap callback of the TextFormField.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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