Flutter_Webview keyboard pop-up problem

Flutter_Webview keyboard pop-up problem


webview_flutter ^0.3.7+1 pub Links

webview_flutter no way the pop-up keyboard on Android, issue on github has been mentioned for a long time, but also to the official 19-year milestone in October Issue # 19 718 , (already have a PR to the master branch As of press time, but the stable branch the students might have to wait a Ha), but PR solution did not use before ... AndroidN the Comment

1. inspiration from other students

Hidden TextField program , simple idea of this program is that in onPageFinishthe time to Webview inject some js code, monitor input / textarea of focus events, and then sent to the hidden behind the WebView TextField by JSChannel, indirectly evoke the soft keyboard by TextField and then, by listening TextField the onChange event to set a new value to the input / textarea

Here is the code for his JS: He needs a few listens the pop input method element of a site with js, focus events / focusout events

inputs = document.getElementsByClassName('search-bar');
                            header=document.getElementsByClassName('site-header');
                            header[0].style.display = 'none';
buttons = document.getElementsByClassName('icon');
                            buttons[0].focus();
                            if (inputs != null) {
                              input = inputs[0];
                              InputValue.postMessage(input.value);
                              input.addEventListener('focus', (_) => {
                                Focus.postMessage('focus');
                              }, true);
                              input.addEventListener('focusout', (_) => {
                                Focus.postMessage('focusout');
                              }, true)
                            }
复制代码

JSChannel:

 javascriptChannels: Set.from(
                          [
                            // Listening for Javascript messages to get Notified of Focuschanges and the current input Value of the Textfield.
                            JavascriptChannel(
                              name: 'Focus',
                              // get notified of focus changes on the input field and open/close the Keyboard.
                              onMessageReceived: (JavascriptMessage focus) {
                                print(focus.message);
                                if (focus.message == 'focus') {
                                  FocusScope.of(context)
                                      .requestFocus(_focusNode);
                                } else if (focus.message == 'focusout') {
                                  _focusNode.unfocus();
                                }
                              },
                            ),
                            JavascriptChannel(
                              name: 'InputValue',
                              // set the value of the native input field to the one on the website to always make sure they have the same input.
                              onMessageReceived: (JavascriptMessage value) {
                                _textController.value =
                                    TextEditingValue(text: value.toString());
                              },
                            )
                          ],
                        ),
复制代码

TextField receive events change the text, by focusNode to evoke / hide the soft keyboard

The program looks good, but the handwriting Classname can monitor all stupid ... and if the user manually close the pop-up keyboard keyboard (pressing the close button on the soft keyboard), will no longer play the soft keyboard does not come out .. .

2. upgrade their programs

  1. TextField alternating with two events to solve the problem after receiving can not turn off the keyboard manually re-evoke the
  2. JS injection monitor all input / textarea element, not listening focus / focusout events, listen for the click event, there are several benefits 1. You can obtain the user's current text selection / cursor position 2. You can click again to judge events
  3. The current focus of the recording element, for determining whether the need to re-evoke a new keyboard

The following simple code implementation:

var inputs = document.getElementsByTagName('input');
var textArea = document.getElementsByTagName('textarea');
var current;

for (var i = 0; i < inputs.length; i++) {
  console.log(i);
  inputs[i].addEventListener('click', (e) => {
    var json = {
      "funcName": "requestFocus",
      "data": {
        "initText": e.target.value,
        "selectionStart":e.target.selectionStart,
        "selectionEnd":e.target.selectionEnd
      }
    };
    json.data.refocus = (document.activeElement == current);
    
    current = e.target;
    var param = JSON.stringify(json);
    console.log(param);
    UserState.postMessage(param);
  })
  
}
for (var i = 0; i < textArea.length; i++) {
  console.log(i);
  textArea[i].addEventListener('click', (e) => {
    var json = {
      "funcName": "requestFocus",
      "data": {
        "initText": e.target.value,
        "selectionStart":e.target.selectionStart,
        "selectionEnd":e.target.selectionEnd
      }
    };
    
    json.data.refocus = (document.activeElement == current);
    
    current = e.target;
    var param = JSON.stringify(json);
    console.log(param);
    
    UserState.postMessage(param);
  })
};
console.log('===JS CODE INJECTED INTO MY WEBVIEW===');
复制代码

UserState is defined jsChannel, receiving a parameter jsonString form, data.initText initial text, selectEnd selectStart text selection position, click Refocus is determined whether re-focus the Element mark, when the element is clicked:

*  先判断是不是refocus,发送给channel
复制代码

Next to process the received data JSChannel which showAndroidKeyboard is a PlatformChannel I have written, to display the soft keyboard, you can also simplify the code, I do not write here, have improved, please contact the author ... also stepped in pit in.

  • The key is to get the focus TextField alternately, when TextField - A get the focus after, for some editing, the user manually shut down the soft keyboard, this time FocusScop.of (context) .requestFocus (focusNodeA) is unable to evoke the keyboard, so you need another TextField-B requests focus,
  • showAndroidKeyboard () to standby in some cases did not get the focus focusNode, we need to manually focus evoke
  • Hide the keyboard events are not a good solution
bool refocus = data['refocus'] as bool;
    if (_focusNode2.hasFocus) {
      if (!refocus) FocusScope.of(context).requestFocus(_focusNode1);
      //FocusScope.of(context).requestFocus(_focusNode);
      if (!_focusNode1.hasFocus) {
        //hideAndroidKeyboard();
        showAndroidKeyboard();
      }
      //把初始文本设置给隐藏TextField
      String initText = data['initText'];
      var selectionStart = data['selectionStart'];
      var selectionEnd = data['selectionEnd'];

      int end = initText.length;
      int start = initText.length;
      if (selectionEnd is int) {
        end = selectionEnd;
      }
      if (selectionStart is int) {
        start = selectionEnd;
      }
      print(selectionEnd);
      textController1.value = TextEditingValue(
        text: initText,
        selection: TextSelection(baseOffset: start, extentOffset: end),
      );
      //TextField请求显示键盘
      FocusScope.of(context).requestFocus(_focusNode1);
    } else {
      if (!refocus) FocusScope.of(context).requestFocus(_focusNode2);
      //FocusScope.of(context).requestFocus(_focusNode);
      if (!_focusNode2.hasFocus) {
        //hideAndroidKeyboard();
        showAndroidKeyboard();
      }
      //把初始文本设置给隐藏TextField
      String initText = data['initText'];
      var selectionStart = data['selectionStart'];
      var selectionEnd = data['selectionEnd'];

      int end = initText.length;
      int start = initText.length;
      if (selectionEnd is int) {
        end = selectionEnd;
      }
      if (selectionStart is int) {
        start = selectionEnd;
      }
      print(selectionEnd);
      textController2.value = TextEditingValue(
        text: initText,
        selection: TextSelection(baseOffset: start, extentOffset: end),
      );
      //TextField请求显示键盘
      FocusScope.of(context).requestFocus(_focusNode2);
    }
复制代码

Hidden behind webview TextField

return Stack(
                  children: <Widget>[
                    TextField(
                      autofocus: false,
                      focusNode: _focusNode1,
                      controller: textController1,
                      onChanged: (text) {
                        controller.evaluateJavascript('''
                         if(current != null){
                          current.value = '${textController1.text}';
                          current.selectionStart = ${textController1.selection.start};
                          current.selectionEnd = ${textController1.selection.end};
                          current.dispatchEvent(new Event('input'));
                         }
                        ''');
                      },
                      onSubmitted: (text) {
                        controller.evaluateJavascript('''
                        if(current != null)
                          current.submit();
                        ''');
                        _focusNode1.unfocus();
                      },
                    ),
                    TextField(
                      autofocus: false,
                      focusNode: _focusNode2,
                      controller: textController2,
                      onChanged: (text) {
                        controller.evaluateJavascript('''
                         if(current != null){
                          current.value = '${textController2.text}';
                          current.selectionStart = ${textController2.selection.start};
                          current.selectionEnd = ${textController2.selection.end};
                          current.dispatchEvent(new Event('input'));
                         }
                        ''');
                      },
                      onSubmitted: (text) {
                        controller.evaluateJavascript('''
                        if(current != null)
                          current.submit();
                        ''');
                        _focusNode2.unfocus();
                      },
                    ),
                    WebView(....)
                  ]
  );
复制代码
  • In TextField onChange adaptation of the focus of the current Element text / selection, then send an input event to trigger Element change current.dispatchEvent(new Event('input'));, where we should have a good understanding.

Have to say Google is too pit, webview actually have such a big flaw, but there is no way, after all, not the version number to 1.0.0 of this method ... it is only a temporary solution, such as clicking a blank to hide the soft keyboard features not implemented using only webview simple text input is still possible, and some input label as a button hidden under the keyboard may have to manually, or more.

Reproduced in: https: //juejin.im/post/5cfa30b56fb9a07ebf4b6097

Guess you like

Origin blog.csdn.net/weixin_34293141/article/details/91470579