【问题标题】:How to display a local image before webview is successfully loaded in Flutter?如何在 Flutter 中成功加载 webview 之前显示本地图像?
【发布时间】:2019-12-06 10:13:08
【问题描述】:

在 Flutter 中,我想在加载 webview 之前显示本地图像。如果用户没有打开他们的wifi,将显示一个图像而不是一个空白的白色屏幕(ios)或一个错误消息说无法连接到所述网页(android)。

我正在为这个应用使用官方的 webview_flutter 包。

以下是我尝试过的代码,但它适用于 ios 但不适用于 android。在 Android 中,当我关闭 wifi 并启动应用程序时,会显示一条显示 webview 链接的错误消息。

编辑:wifi 连接并按下重新加载按钮后不会从图像更改为 webview。

final webViewKey1 = GlobalKey<WebViewContainerState>();
var _url = 'http://www.google.com';
final _key = UniqueKey();
bool _isLoadingPage;

class WebViewPage extends StatefulWidget {
  @override
  WebViewPageState createState() => WebViewPageState();
}

class WebViewPageState extends State<WebViewPage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Screen 1'),
        leading: IconButton(
          icon: Icon(Icons.menu),
          onPressed: (){
            Scaffold.of(context).openDrawer();
          },
        ),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.refresh), 
            color: Colors.white,
            onPressed: () {
              webViewKey1.currentState?.reloadWebView();
            },
          ),
        ]
      ),
      body: 
          WebViewContainer(key: webViewKey1),   
    );
  }
}

class WebViewContainer extends StatefulWidget {
  WebViewContainer({Key key}) : super(key: key);

  @override
  WebViewContainerState createState() => WebViewContainerState();
}

class WebViewContainerState extends State<WebViewContainer> {
  WebViewController _webViewController;

  void initState() {
    super.initState();
    _isLoadingPage = true;
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
        children: <Widget>[
          Opacity(opacity: _isLoadingPage?0:1, child: WebView(
            key: _key,
            initialUrl: _url,
            javascriptMode: JavascriptMode.unrestricted,
            onWebViewCreated: (controller) {
              _webViewController = controller;
            },
            onPageFinished: (finish) {
              setState(() {
                _isLoadingPage = false;
              });
            },
          ),
          ),
          _isLoadingPage
            ? Container(
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: AssetImage('assets/images/fail.png'),
                  fit: BoxFit.fill,
                ),
              ),
            )
            : Container(
              color: Colors.transparent,
            ),
        ],
      );
  }

  void reloadWebView() {
    _webViewController?.reload();
  }
}

【问题讨论】:

    标签: flutter webview


    【解决方案1】:

    使用不透明度小部件使其不可见并在完成时显示它。

    Opacity(opacity: _isLoadingPage?0:1, child: WebView(
              key: _key,
              initialUrl: _url,
              javascriptMode: JavascriptMode.unrestricted,
              onWebViewCreated: (webViewCreate) {
                _controller.complete(webViewCreate);
              },
              onPageFinished: (finish) {
                setState(() {
                  _isLoadingPage = false;
                });
              },
            ),)
    

    【讨论】:

    • 当我尝试在wifi断开时重新加载webview时,Android上仍然显示错误消息“网页不可用”,有什么解决方法吗?
    【解决方案2】:

    您可以使用 IndexedStack 并在使用 onPageFinished 加载 WebView 后在小部件之间切换。您可以使用connectivity 插件来检查连接。

    ConnectivityResult _connectionStatus;
      final Connectivity _connectivity = Connectivity();
      StreamSubscription<ConnectivityResult> _connectivitySubscription;
      int _page = 1;
    
      @override
      void initState() {
        super.initState();
        initConnectivity();
        _connectivitySubscription =
            _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
      }
    
      @override
      void dispose() {
        _connectivitySubscription.cancel();
        super.dispose();
      }
    
      Future<void> initConnectivity() async {
        ConnectivityResult result;
        // Platform messages may fail, so we use a try/catch PlatformException.
        try {
          result = await _connectivity.checkConnectivity();
        } on PlatformException catch (e) {
          print(e.toString());
        }
    
        // If the widget was removed from the tree while the asynchronous platform
        // message was in flight, we want to discard the reply rather than calling
        // setState to update our non-existent appearance.
        if (!mounted) {
          return;
        }
    
        _updateConnectionStatus(result);
      }
    
      @override
      Widget build(BuildContext context) {
        print(_connectionStatus);
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: IndexedStack(
            index: _page,
            children: <Widget>[
              WebView(
                initialUrl: 'https://www.google.com/',
                onPageFinished: (_) {
                  if (_connectionStatus != ConnectivityResult.none) {
                    setState(() {
                      _page = 0;
                    });
                  }
                },
              ),
              Container(
                child: Center(
                  child: Text('Some Image'),
                ),
              ),
            ],
          ),
        );
      }
    
      Future<void> _updateConnectionStatus(ConnectivityResult result) async {
        switch (result) {
          case ConnectivityResult.wifi:
          case ConnectivityResult.mobile:
          case ConnectivityResult.none:
            setState(() => _connectionStatus = result);
            break;
          default:
            setState(() => _connectionStatus = result);
            break;
        }
      }
    
    

    【讨论】:

    • 当我尝试在wifi断开时重新加载webview时,Android上仍然显示错误消息“网页不可用”,有什么解决方法吗?
    • 我已经更新了答案。在这里,我正在检查连接并更新小部件。
    • 连接wifi时图像不会重新加载以显示webview,即使我按下重新加载按钮,图像也会卡住并且不显示webview,知道为什么会这样吗?跨度>
    • 代码在编辑中,我试过你的方法,但是即使连接了wifi,当我启动应用程序时它也会显示图像
    【解决方案3】:

    您可以使用我的插件flutter_inappwebview,它有很多事件,包括在 WebView 加载 url(onLoadError 事件)和接收 HTTP 时管理错误的事件(例如 net::ERR_ADDRESS_UNREACHABLE)错误,例如 403、404 等(onLoadHttpError 事件)。

    您可以使用connectivity 插件通过订阅连接插件公开的流来监听网络状态变化。

    此外,您可以使用 IndexedStack 并在使用 onLoadStop 加载 WebView 后在小部件之间切换。

    完整示例:

    import 'dart:async';
    import 'dart:io';
    
    import 'package:flutter/material.dart';
    
    import 'package:connectivity/connectivity.dart';
    import 'package:flutter_inappwebview/flutter_inappwebview.dart';
    
    Future main() async {
      runApp(new MyApp());
    }
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => new _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      void dispose() {
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            home: InAppWebViewPage()
        );
      }
    }
    
    class InAppWebViewPage extends StatefulWidget {
      @override
      _InAppWebViewPageState createState() => new _InAppWebViewPageState();
    }
    
    class _InAppWebViewPageState extends State<InAppWebViewPage> {
      InAppWebViewController webView;
      int _page = 2;
      bool _loadError = false;
      StreamSubscription<ConnectivityResult> subscription;
    
      @override
      initState() {
        super.initState();
        subscription = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) {
          if (result != ConnectivityResult.none && webView != null) {
            print("reload");
            _loadError = false;
            webView.reload();
          }
        });
      }
    
      @override
      dispose() {
        super.dispose();
        subscription.cancel();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text("InAppWebView")
            ),
            body: IndexedStack(
              index: _page,
              children: <Widget>[
                InAppWebView(
                  initialUrl: "https://flutter.dev",
                  initialHeaders: {},
                  initialOptions: InAppWebViewWidgetOptions(
                      inAppWebViewOptions: InAppWebViewOptions(
                        clearCache: true,
                        debuggingEnabled: true,
                      ),
                  ),
                  onWebViewCreated: (InAppWebViewController controller) {
                    webView = controller;
                  },
                  onLoadStart: (InAppWebViewController controller, String url) {
    
                  },
                  onLoadStop: (InAppWebViewController controller, String url) {
                    print(url);
                    setState(() {
                      if (!_loadError) {
                        _page = 0;
                      } else {
                        _page = 1;
                      }
                    });
                  },
                  onLoadError: (InAppWebViewController controller, String url, int code, String message) async {
                    print("error $url: $code, $message");
                    _loadError = true;
                  },
                  onLoadHttpError: (InAppWebViewController controller, String url, int statusCode, String description) async {
                    print("HTTP error $url: $statusCode, $description");
                  },
                ),
                (Platform.isAndroid) ? Container(
                    child: Text("My custom error message"),
                ) : Container(
                    decoration: BoxDecoration(
                      image: DecorationImage(
                        image: AssetImage('assets/images/fail.png'),
                        fit: BoxFit.fill,
                      ),
                    )
                ),
                Container(
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: AssetImage('assets/images/loading.jpg'),
                      fit: BoxFit.fill,
                    ),
                  )
                )
              ],
            ),
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-03-19
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多