每当键盘打开或关闭时,我的 flutter 应用程序就会重建

问题描述 投票:0回答:2

每当我关闭键盘时,我在

TextField
中写入的文本就会被重置/清空。 在试图找出导致此行为的问题时,我开始了解到打开和关闭
TextField
会导致应用程序重建。

这是我遇到问题的代码:

part of quizui;

class ShowDescription extends StatefulWidget {
  const ShowDescription({Key? key,required this.descriptionAsString,required this.isItForFB,required this.isForResult}) : super(key: key);

  final bool isForResult;
  final bool isItForFB;
  final String descriptionAsString;

  @override
  State<ShowDescription> createState() => _ShowDescriptionState();
}

class _ShowDescriptionState extends State<ShowDescription> {
  List<dynamic> descriptionData = [];
  int tempIndex = 0;
  late InAppWebViewController webView;
  InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
    crossPlatform: InAppWebViewOptions(
      useShouldOverrideUrlLoading: true,
      mediaPlaybackRequiresUserGesture: false,
    ),
    android: AndroidInAppWebViewOptions(
      useHybridComposition: true,
    ),
    ios: IOSInAppWebViewOptions(
      allowsInlineMediaPlayback: true,
    ),
  );

  List <TextEditingController> textControllers = [];

  @override
  void initState(){
    super.initState();
    WidgetsBinding.instance?.addPostFrameCallback((_) {
      FillInTheBlankWidgetState.callBackDescription = (){
        textControllerListForFB.clear();
        print("description callback running");
        for(TextEditingController i in textControllers){
          textControllerListForFB.add(i.text);
        }
      };
    });
  }

  @override
  void dispose() {
    for (var controller in textControllers) {
      controller.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    print("Rebuilding Show Description-----");
    if (widget.descriptionAsString != "") {
      descriptionData = jsonDecode(widget.descriptionAsString);
    }
    // textControllers.clear();
    tempIndex = 0;
    return Container(
      padding: EdgeInsets.symmetric(vertical: 5,horizontal: 8),
      alignment: Alignment.centerLeft,
      // color: Colors.grey.shade200,
      width: MediaQuery.of(context).size.width,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: descriptionData.map<Widget>((item) {
          switch (item['type']) {
            case 'text':
              if(widget.isItForFB){
                String src = item['data']['src'];
                List<String> parts = src.split('##');
                List<InlineSpan> children = [];

                for (int i = 0; i < parts.length; i++) {
                  if (i % 2 == 0) {
                    // Text outside the ##
                    children.add(
                      TextSpan(text: parseFragment(parts[i]).text)
                    );
                  } else {
                    // TextField inside the ##
                    TextEditingController controller = TextEditingController(text: (widget.isForResult)?(selectedAnswerOfFB!=[])?selectedAnswerOfFB[tempIndex].toString():"":"");
                    // TextEditingController controller = TextEditingController(text: (widget.isForResult)? selectedAnswerOfFB[tempIndex].toString():"");
                    tempIndex++;
                    textControllers.add(controller);
                    children.add(
                      WidgetSpan(
                        child: SizedBox(
                          width: 110,
                          height: 40,
                          child: TextField(
                            controller: controller,
                            enabled: (!widget.isForResult),
                            decoration: InputDecoration(
                              // border: OutlineInputBorder(),
                          ),style: TextStyle(fontSize: 14),
                        ),
                      ),
                    ));
                  }
                }
                return Padding(
                  padding: const EdgeInsets.all(0.0),
                  child: RichText(
                    text: TextSpan(children: children,style: TextStyle(color: Colors.black)),
                  ),
                );
              }
              else{
                return Padding(
                  padding: const EdgeInsets.all(5.0),
                  child:
                  Html(
                    data: item['data']['src'],
                  ),
                  // Text(
                  //   item['data']['src']
                  //       .replaceAll(RegExp('<p>|<\/p>'), '\n').replaceAll(RegExp('amp;'), ''),
                  // ),
                );
              }

            case 'image':
              return Image.network(
                item['data']['rootUrl'] + '/' + item['data']['src'],
              );

            case 'embed':
              String htmlString = item["data"]["src"].toString();
              var regExp = RegExp('src="([^"]+)"');

              var match = regExp.firstMatch(htmlString);

              if (match != null) {
                var srcUrl = match.group(1);
                return customWebViewWIdget(context, srcUrl);
              } else {
                print('No match found.');
                return Container();
              }
            default:
              return Container();
          }
        }).toList(),
      ),
    );
  }

  Container customWebViewWIdget(BuildContext context, URL) {
    return Container(
      padding: EdgeInsets.all(10),
      height: MediaQuery.of(context).size.width,
      width: MediaQuery.of(context).size.width,
      child: InAppWebView(
        initialOptions: options,
        shouldOverrideUrlLoading: (controller, navigationAction) async {
          if (navigationAction.request.url == "url"){
            print("if loop running");
            return NavigationActionPolicy.CANCEL;
          }
          return NavigationActionPolicy.ALLOW;
        },
        androidOnPermissionRequest: (controller, origin, resources) async {
          return PermissionRequestResponse(
            resources: resources,
            action: PermissionRequestResponseAction.GRANT,
          );
        },
        initialUrlRequest: URLRequest(url: Uri.parse(URL)),
        onWebViewCreated: (InAppWebViewController controller) {
          webView = controller;
        },
      ),
    );
  }
}

这里 isItForFB 为 true,isFor result 为 false,唯一重要的部分是 textField 的相关位置。 我对 flutter 很陌生,之前也遇到过这个问题,我想我应该使用 globalKey ,但不知道具体如何以及在哪里。

flutter keyboard rebuild
2个回答
2
投票

是的,这是 Flutter 应用程序中的常见问题。当键盘打开或关闭时,MediaQuery.of(context) 值发生变化,从而触发 widget 树的重建。这可能会消耗性能,尤其是当您的应用程序有很多小部件时。

有几种方法可以防止键盘打开或关闭时重建小部件树。一种方法是使用 MediaQueryData.viewInsets 属性获取键盘的插入,然后使用此信息相应地更新小部件的布局。另一种方法是使用 InheritedWidget 模式与应用程序中的所有小部件共享键盘插入。

请参阅此相关问题:问题它将帮助您


0
投票

有时使用时会发生这种情况

MediaQuery.of(context)
drawerEdgeDragWidth
 中的 
scaffold

争论
© www.soinside.com 2019 - 2024. All rights reserved.