键盘显示时树重建

tree rebuilds when keyboard shows

我正在为我的应用程序使用 responsive_sizer 包..

当键盘以文本字段打开时,我的整个树被重建。

这里是文本字段的代码:


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

在 Sizer() 中,我有:

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 包含在


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(),
                                    ),

我在导入 responsive_sizer 后遇到了这个问题...我不明白问题出在哪里。 我尝试了 resizetoavoidbottominset 但没有任何改变。

我发现了问题。它不是来自 MediaQuery,而是来自 Responsive_sizer 包。

当我打开键盘时,我实际上更新了高度和宽度。但是这个包必须以下列方式包含您的 MaterialApp:

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

这就是问题所在。在我的主页下,我有一个流来查看用户是否已登录,然后会转到个人资料页面等。我不希望它重新加载,我只希望配置文件重新加载。

我的解决方案:我使用 MediaQuery 的方式与 Responsive_sizer 类似。我没有使用 .h 和 .w 包,而是使用 MediaQuery.of(context).size.height 及其对应物。字体大小也是一样。

希望能帮到和我有相同问题的朋友, 晚上好