Flutter WebView文本输入框被软键盘遮挡

5

我正在Android上进行测试(我将验证iOS上是否相同)。

我的问题是,当我使用webview显示条纹结帐页面时,如果我点击其中的一个文本输入框以输入底部附近的内容(邮政编码),则虚拟键盘会覆盖webview,并且我无法在webview中向上滚动。

看起来webview像预期的那样占据整个屏幕,但是当软键盘出现时,Flutter通常会为其腾出空间(缩小屏幕上显示的小部件)。 Webview似乎仍然保持相同的大小。

我尝试了一个hack,将webview放在具有动态高度的container()中。 它有点奏效。 以下是代码,关键行是Container()的高度:

height: MediaQuery.of(context).size.height * (MediaQuery.of(context).viewInsets.bottom != 0 ? .7 : 1)

但是这种方法会导致键盘混淆。它会以某种方式欺骗键盘,使其不能用于例如邮政编码的数字输入类型。看起来它尝试了一下,但在分秒钟后重新绘制为非数字键盘。

为什么Webview在手机上无法遵守软键盘?

这是我的有状态小部件中的构建:

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Stack(
        children: [
          initialUrl == null
              ? Container()
              : Container(
                  height: MediaQuery.of(context).size.height * (MediaQuery.of(context).viewInsets.bottom != 0 ? .7 : 1),
                  child: WebView(
                    initialUrl: initialUrl,
                    javascriptMode: JavascriptMode.unrestricted,
                    onPageStarted: (controller) {},
                    onPageFinished: (controller) {
                      Future.delayed(Duration(milliseconds: 1234), () {
                        if (mounted) {
                          showLoading = false;
                          setState(() {});
                        }
                      });
                    },
                    navigationDelegate: (NavigationRequest request) {
                      if (request.url.startsWith('https://example.com/success')) {
                        Navigator.of(context).pop('success');
                      } else if (request.url.startsWith('https://example.com/cancel')) {
                        Navigator.of(context).pop('cancel');
                      }
                      return NavigationDecision.navigate;
                    },
                  ),
                ),
          showLoading == true
              ? Center(
                  child: Container(width: 80, height: 80, child: CircularProgressIndicator()),
                )
              : Container(),
        ],
      ),
    );
  }

以下是屏幕截图。请注意,在键盘截图中,您甚至无法滚动 Webview 以查看您正在输入的邮政编码...

enter image description here enter image description here

4个回答

11
对我来说,答案有两点。
首先,使用此行代码,在显示 webview 的有状态小部件中设置 WebView.platform。请注意,它是针对我在 Android 上测试时的情况而特定的,因此可能对于其中一些人,当您未看到该问题时,您可能在 iOS 上?
  @override
  void initState() {
    super.initState();
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView(); // <<== THIS
  }

其次,我添加了一个Scaffold,并将resizeToAvoidBottomInset设置为true,同时删除了我对此的使用:

height: MediaQuery.of(context).size.height * (MediaQuery.of(context).viewInsets.bottom != 0 ? .7 : 1),`

这是带有Webview的主体代码:
@override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Stack(
        children: [
          initialUrl == null
              ? Container()
              : Scaffold(
                resizeToAvoidBottomInset: true,
                body: WebView(
                  initialUrl: initialUrl,
                  javascriptMode: JavascriptMode.unrestricted,
                  onPageStarted: (controller) {},
                  onPageFinished: (controller) {
                    Future.delayed(Duration(milliseconds: 1234), () {
                      if (mounted) {
                        showLoading = false;
                        setState(() {});
                      }
                    });
                  },
                  navigationDelegate: (NavigationRequest request) {
                    if (request.url.startsWith('https://example.com/success')) {
                      Navigator.of(context).pop('success');
                    } else if (request.url.startsWith('https://example.com/cancel')) {
                      Navigator.of(context).pop('cancel');
                    }
                    return NavigationDecision.navigate;
                  },
                ),
              ),
          showLoading == true
              ? Center(
                  child: Container(width: 80, height: 80, child: CircularProgressIndicator()),
                )
              : Container(),
        ],
      ),
    );
  }

4

通过使用“gestureRecognizers”属性将滚动手势移动到Webview本身,这是一种更简单的方法:

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Webview Example',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Webview Example'),
        ),
        body: Stack(
          children: [
            //... widgets that render behind the column
            WebView(
              initialUrl: 'https://inputtypes.com',
              javascriptMode: JavascriptMode.unrestricted,
              gestureRecognizers: Set()
                ..add(
                  Factory<DragGestureRecognizer>(
                    () => VerticalDragGestureRecognizer(),
                  ),
                ),
            ),
          ],
        ),
      ),
    );
  }
}

尝试一下,看看它是否解决了你的问题


0

你试过用 SingleChildScrollView 包裹你的小部件吗?


是的,我尝试过了。由于webview被无限制地(不)约束,这会导致渲染问题。我想我可以尝试将其放入一个屏幕大小的容器中,然后再放入SingleChildScrollView中。 - Eradicatore
也许您可以使用列而不是具有特定高度的容器。 - Younss AIT MOU
很不幸,它没有帮助。而且还有31个像素的溢出,我猜测是由于SafeArea()引起的。 - Eradicatore
它对我有用,我将代码发布为答案以获得更好的代码格式化 ;) - Younss AIT MOU

0
这对我有用:
Scaffold(
      body: Stack(
        children: [
          //... widgets that render behind the column
          Align(
            alignment: Alignment.center,
            child: SingleChildScrollView( 
              child: Column(
                 children: [
                    //... login form inputs and buttons
                 ]
              ),
            ),
          ),
        ],
      ),
    );

1
你尝试使用Webview了吗?你指向了哪个网站?你能展示一张键盘显示和不显示的网页截图,以便我看到它是否正常工作吗? - Eradicatore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接