Whenever keyboard is opend or closed, my flutter app gets rebuild

847 Views Asked by At

Whenever I close the keyboard the text I write in TextField gets reset / empty. While trying to figure out the issue causing this behavior I came to understand that opening and closing of TextField causes the app to rebuild.

Here is the code where I am facing the issue :

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

here isItForFB is true and isFor result is false, the only part important is where textField is related. I am really new to flutter and have faced this issue once earlier also, i think i should use globalKey , but does not know exectly how and where.

1

There are 1 best solutions below

0
Mohamad Easwy On

Yes, this is a common issue in Flutter apps. When the keyboard is opened or closed, the MediaQuery.of(context) value changes, which triggers a rebuild of the widget tree. This can be a performance drain, especially if your app has a lot of widgets.

There are a few ways to prevent the widget tree from being rebuilt when the keyboard is opened or closed. One way is to use the MediaQueryData.viewInsets property to get the insets of the keyboard, and then use this information to update the layout of your widgets accordingly. Another way is to use the InheritedWidget pattern to share the keyboard insets with all of the widgets in your app.

see this related question : problem it will help you