2

I'm building my first Flutter app. The app is a BottomNavigationBar - every tab need to load different URL. The easiest app in the world. The problem is that for some reason the webview_flutter won't reload the url, it's stock on the initialUrl

any suggestions? Thanks!

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

const String _tabOneUrl = 'https://stackoverflow.com/';
const String _tabTwoUrl = 'https://www.youtube.com/';
const String _tabThreeUrl = 'https://www.google.com/';
const String _tabFourUrl = 'https://en.wikipedia.org/wiki/Kraken';

void main() => runApp(new MaterialApp(
      title: 'MY FIRST APP',
      home: new LoadWebView(),
    ));

class TabObject {
  final int index;
  final Text title;
  final String url;
  final Icon icon;

  const TabObject({this.index, this.title, this.url, this.icon});
}

const List<TabObject> tabsList = <TabObject>[
  const TabObject(
      index: 0,
      title: const Text('Page 1'),
      url: _tabOneUrl,
      icon: const Icon(Icons.looks_one)),
  const TabObject(
      index: 1,
      title: const Text('Page 2'),
      url: _tabTwoUrl,
      icon: const Icon(Icons.looks_two)),
  const TabObject(
      index: 2,
      title: const Text('Page 3'),
      url: _tabThreeUrl,
      icon: const Icon(Icons.looks_3)),
  const TabObject(
      index: 3,
      title: const Text('Page 4'),
      url: _tabFourUrl,
      icon: const Icon(Icons.looks_4)),
  const TabObject(
      index: 4,
      title: const Text('Page 5'),
      url: _tabThreeUrl,
      icon: const Icon(Icons.looks_5))
];

class LoadWebView extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new LoadWebViewState();
  }
}

class LoadWebViewState extends State<LoadWebView> {
  int _bottomNavBarIndex = 0;
  TabObject _tabObject = tabsList[0];
  bool _isFromInit = true;

  Completer<WebViewController> _controller = Completer<WebViewController>();



  void _selectedTab(TabObject tabObject) {
    setState(() {
      _isFromInit = false;
      _bottomNavBarIndex = tabObject.index;
      _tabObject = tabObject;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Web Nail'),
        actions: <Widget>[],
      ),

      body: new WebViewClass(tabObject: _tabObject, controller: _controller,isFromInit:_isFromInit),
      bottomNavigationBar: new BottomNavigationBar(
        currentIndex: _bottomNavBarIndex,
        type: BottomNavigationBarType.fixed,
        onTap: (int index) {
          setState(() {
            _selectedTab(tabsList[index]);
          });
        },
        items: [
          new BottomNavigationBarItem(
            icon: tabsList[0].icon,
            title: tabsList[0].title,
          ),
          new BottomNavigationBarItem(
            icon: tabsList[1].icon,
            title: tabsList[1].title,
          ),
          new BottomNavigationBarItem(
            icon: tabsList[2].icon,
            title: tabsList[2].title,
          ),
          new BottomNavigationBarItem(
            icon: tabsList[3].icon,
            title: tabsList[3].title,
          ),
          new BottomNavigationBarItem(
            icon: tabsList[4].icon,
            title: tabsList[4].title,
          ),
        ],
      ),
    );
  }
}

class WebViewClass extends StatelessWidget {
  final TabObject tabObject;
  final Completer<WebViewController> controller;
  final bool isFromInit;

  WebViewClass({this.tabObject, this.controller,this.isFromInit});

  @override
  Widget build(BuildContext context) {
    return new WebView(
        initialUrl: tabObject.url,
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webViewController) {
          controller.complete(webViewController);
        });
  }
}

is there a way to force recreate the web view after the BottomNavigationBar on tap? does Flutter is mature enough to handle this simple app?

digitalmidges
  • 826
  • 3
  • 13
  • 24
  • If you're new to a framework, consider whether it's more likely a problem with your understanding or a problem with the framework. – Lucas Jun 23 '19 at 10:49

2 Answers2

0

Try adding a key to your WebViewClass

WebViewClass({Key key, this.tabObject, this.controller,this.isFromInit}) : super(key: key);

Then in the build:

body: new WebViewClass(key: ObjectKey(_tabObject.index), tabObject: _tabObject, controller: _controller,isFromInit:_isFromInit),

Also, after you solve this you should move the state down into the WebViewClass - calling setState on the whole MaterialApp rebuilds it and will make your app slow.

Lucas
  • 2,472
  • 2
  • 18
  • 33
  • Thank Lucas, unfortunately, I am getting this error: Unhandled Exception: Bad state: Future already completed – digitalmidges Jun 23 '19 at 20:14
  • I guess when you change tab, it is creating a new webview with the new address but trying to use the same Future which is already completed. You either have to use a new future, or refactor you code so changing tabs changes the page instead of creating a new WebView – Lucas Jun 24 '19 at 22:21
  • It should be enough to create a new Completer when you change tabs. This doesn't seem like an ideal solution though, I'd have a look at some other projects to see how they get the WebViewController. – Lucas Jun 24 '19 at 22:27
0

After lots of struggle, I found a solution just by using the IndexedStack, It will work smoothly.

body:IndexedStack(
              index: _selectedIndex ,
              children: <Widget>[
               MyHomePage(),
               Webview("Url1"),
               Webview("Url2"),
               //etc...
              ]
            ),

This solution I found from this link, overview once, you will get to know more.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Spsnamta
  • 479
  • 6
  • 11