flutterdartresponsiverebuild

tree rebuilds when keyboard shows


I'm using responsive_sizer package for my app..

my whole tree is rebuilt when the keyboard opens with a textfield.

Here the code of the textfield :


class ProfileNameTextField extends StatefulWidget {
  const ProfileNameTextField({Key? key}) : super(key: key);

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

class _ProfileNameTextFieldState extends State<ProfileNameTextField> {
  TextEditingController? _controller;
  String _previousName = "";
  FocusNode? _focusNode;
  final String _forbiddenCharacters = "1234567890&)°(+=/,;.£\$*€<>\_#@";
  Widget _subText = Container();

  @override
  void initState() {
    // TODO: implement initState
    _controller = TextEditingController();
    _previousName = CloudUser.instance.username;
    _controller!.text = CloudUser.instance.username;
    _focusNode = FocusNode();
    _focusNode!.addListener(() {
      if(!_focusNode!.hasFocus) {
        print("Focus on name textfield is lost");
        _onSubmitted(_controller!.text);
      }
    });
    super.initState();
  }

  @override
  void dispose() {
    // Clean up the focus node when the Form is disposed.
    _focusNode!.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    Widget? _suffix;


    switch(Provider.of<LoadingProvider>(context).state) {
      case LoadingState.busy:
        _suffix = SpinKitRing(
          color: Theme
              .of(context)
              .primaryColor,
          lineWidth: 2,
          size: Theme.of(context).textTheme.subtitle1!.fontSize!
        );
        break;
      case LoadingState.idle:
        _suffix = Container();
        break;
    }

    return CustomTextContainer(
        child: InkWell(
            onTap: _giveFocus,
            child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children:
                [
                  Text(
                      "Prénom",
                      style: Theme.of(context).textTheme.bodyText2!.copyWith(
                        fontSize: Theme.of(context).textTheme.bodyText2!.fontSize!.sp
                      )
                  ),
                  Container(height: Sizer().heightSmallSpace),
                  Container(height: Theme.of(context).textTheme.bodyText1!.fontSize,
                    child: Row(children: [
                      Expanded(
                        child: TextField(
                          keyboardType: TextInputType.name,
                          controller: _controller,
                          onSubmitted: _onSubmitted,
                          focusNode: _focusNode,
                          decoration: InputDecoration(
                              isDense: true,
                              contentPadding: EdgeInsets.zero,
                          ),
                          style: Theme.of(context).textTheme.bodyText1!.copyWith(
                              color: Theme.of(context).primaryColor,

                              fontWeight: FontWeight.w600,
                              fontSize: Theme.of(context).textTheme.bodyText1!.fontSize!.sp
                          ),
                          textAlign: TextAlign.start,
                        ),),
                      _suffix,
                    ]),
                  ),
                  Container(height: Sizer().heightSmallSpace),
                  Row(children: [
                    Spacer(),
                    Container(
                        height: Theme.of(context).textTheme.subtitle1!.fontSize!*1.2,
                        child: Center(child: _subText)),
                  ]),
                  Container(height: Sizer().heightSmallSpace),
                ]
            )
        )
    );
  }

  _onSubmitted(String username) {
    RegExp regExp = RegExp('[' + _forbiddenCharacters + ']');
    if(!regExp.hasMatch(username)) {
      if(_previousName != username) {
        print("name is " + username);
        _previousName = username;
        setState(() {
          _subText = Container();
        });
        Provider.of<LoadingProvider>(context, listen: false).update('username', username).then((result) {
          if(result) {
            CloudUser.instance.username = username;
            setState(() {
              _subText = Text(
                "Enregistré",
                style: Theme
                    .of(context)
                    .textTheme
                    .subtitle1!
                    .copyWith(
                    color: color.success,
                    fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
                ),
              );
            });
          }
          else
            setState(() {
              _subText = Text(
                "Erreur serveur",
                style: Theme.of(context).textTheme.subtitle1!.copyWith(
                    color: Theme.of(context).errorColor,
                    fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
                ),
              );
            });
        });
      }
    } else {
      setState(() {
        _subText = Text(
          "Caractères interdits",
          style: Theme.of(context).textTheme.subtitle1!.copyWith(
              color: Theme.of(context).errorColor,
              fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
          ),
          textAlign: TextAlign.right,
        );
      });
    }
  }

  _giveFocus() {
    _focusNode!.requestFocus();
  }
}

Within Sizer(), i have :

double padding = 2.h;

  double widgetHeight = 8.h;

  double iconButton = 4.h;

  double radius = 15;

  double lineWidth = 3.h;

  double heightSpace = 3.h;

  double heightSmallSpace = 0.9.h;

  double gridSpacing = 0.3.h;

  double widthSpace = 1.25.w;

ProfileNameTextField is included in


class _ProfileControllerState extends State<ProfileController> {
  @override
  Widget build(BuildContext context) {
    return Container(
        color: Theme.of(context).backgroundColor,
        child: Column(
            children: [
              ProfileAppBar(
                onSetting: _onSetting,
              ),
              Flexible(
                  child: Container(
                      padding: EdgeInsets.symmetric(horizontal: Sizer().padding/3),
                      color: Theme.of(context).scaffoldBackgroundColor,
                      child: Scrollbar(
                          child: SingleChildScrollView(
                              physics: ClampingScrollPhysics(),
                              child: Container(
                                  padding: EdgeInsets.symmetric(horizontal: Sizer().padding*2/3),
                                  child: Column(children:
                                  [
                                    Container(height: Sizer().heightSpace),
                                    SvgPicture.asset(
                                      "assets/icons/phone_kisses.svg",
                                      height: Sizer().widgetHeight*3,
                                      width: Sizer().getCustomWidth(66),
                                      fit: BoxFit.contain,
                                    ),
                                    _space(),
                                    ChangeNotifierProvider<LoadingProvider>(
                                      create: (BuildContext context) => LoadingProvider(),
                                      child: ProfileNameTextField(),
                                    ),

I have this problem since the import of the responsive_sizer... I do not understand where the problem can come from. I tried resizetoavoidbottominset but nothing changed.


Solution

  • I found the problem. It's not coming from MediaQuery, but from the Responsive_sizer package.

    When I open the keyboard, I actually update the height and width. But this package must necessarily encompass your MaterialApp in the following way:

        MaterialApp(
     home: ResponsiveSizer(
       builder: (context, orientation, screenType) {
         return const HomePage();
       },
     ),
    );
    

    And that's the problem. Under my homepage, I have a stream to see if the user is logged in, which then leads to the profile page, among other things. I don't want it to reload, I just want the profile to reload.

    My solution: I use MediaQuery in a similar way to Responsive_sizer.... instead of using the .h and .w package, I use MediaQuery.of(context).size.height and its counterpart. The same thing for the font size.

    I hope this can help those who have the same problem as me on this package, good evening.