Search code examples
androidflutterdartandroid-webview

Reload WebView every time when hitting buttons at bottom navbar in flutter


I'm building my first web app using Flutter Webview in which I embedded a bottom Navigation bar that further has 4 Icons.

here

Each Icon has its Own Class and by pressing on it launches a different Webview for each tab like the below example:

here

But the problem that I am facing right above is that you can see each tab cannot be pressed more than once at a time. What I'm looking for is to reopen the same tab like a hyperlink in html instead of once only.

here

Also, I have no idea how to refresh webview page when hitting the refresh icon no matter what page or tab I'm

main.dart

import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:splash_screen_view/SplashScreenView.dart';
import 'pages/home_page.dart';
import 'pages/profile.dart';
import 'pages/cart.dart';



void main(){
  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
    statusBarColor: Color(0xff1e2229)
  ));
   runApp(MyApp());
   
}

 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
     
        Widget spalshfirst = SplashScreenView(
              navigateRoute: WebViewClass(),
              duration: 3000,
              imageSize: 80,
              imageSrc: 'assets/splash.png',
              text: "Food Delivery",
              textType: TextType.TyperAnimatedText,
              textStyle: TextStyle(
                fontSize: 25.0,
              ),
              colors: const [
                Colors.purple,
                Colors.blue,
                Colors.yellow,
                Colors.red,
              ],
              backgroundColor: Colors.white,
            );

    return  MaterialApp(
            debugShowCheckedModeBanner: false,
            home:  Scaffold(
                       body: spalshfirst 
                      )
              );
  
  }
}
 
class WebViewClass extends StatefulWidget {
  WebViewState createState() => WebViewState();
}

class WebViewState extends State<WebViewClass> with TickerProviderStateMixin{
 
  @override
   void initState() {
     super.initState();
         // Enable hybrid composition.
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
   }


 int currentIndex = 0;
  @override
  Widget build(BuildContext context) {

//Including Dart Webview pages
     final screens = [
        HomeClass(),
        Center(child: Text('refresh')),
        ProfileClass(),
        CartClass()
     ];


    return  Scaffold(
          resizeToAvoidBottomInset: true,
          appBar: null,
          body: SafeArea(
            child: screens[currentIndex]
          ),
         bottomNavigationBar: BottomNavigationBar(
            currentIndex: currentIndex,
            selectedItemColor: Colors.white,
            unselectedItemColor: Colors.white60,
            onTap: (index) => setState(() => currentIndex = index),
            items: const [
                  BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.home),
                  label: 'Home',
                  backgroundColor: Colors.pink       
                ),
                BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.refresh),
                  label: 'Refresh',
                  backgroundColor: Colors.pink
                ),
                BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.profile_circled),
                  label: 'Profile',
                  backgroundColor: Colors.pink
                ),
                 BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.cart),
                  label: 'Cart',
                  backgroundColor: Colors.pink
                )
            ],

        ) ,
    );
  }

}

Webview HomeClass() refrence

import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';


class HomeClass extends StatefulWidget {
  Homestate createState() => Homestate();
}

class Homestate extends State<HomeClass> with TickerProviderStateMixin{
  late WebViewController _controller;
  final Completer<WebViewController> _controllerCompleter =  Completer<WebViewController>();
  //Make sure this function return Future<bool> otherwise you will get an error
  Future<bool> _onWillPop(BuildContext context) async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
      return Future.value(false);
    } else {
      return Future.value(true);
    }
  }

 bool isLoading = false;
 final key = UniqueKey();
 int position = 0;

  @override
  Widget build(BuildContext context) {
   return WillPopScope(
      onWillPop: () => _goBack(context),
      child: Scaffold(
              appBar: null,
              body: IndexedStack(
                    index: position,
                    children: [
                                WebView(
                                  initialUrl: 'https://google.com',
                                  javascriptMode: JavascriptMode.unrestricted,
                                  key: key,
                                  onPageStarted: (value) {
                                    setState(() {
                                      position = 1;
                                    });
                                  },
                                  onPageFinished: (value) {
                                    setState(() {
                                      position = 0;
                                    });
                                  },
                                  onWebViewCreated: (WebViewController webViewController) {
                                    _controllerCompleter.future.then((value) => _controller = value);
                                    _controllerCompleter.complete(webViewController);
                                  },
                                ),
                                Container(
                                  width: MediaQuery.of(context).size.width,
                                  height: MediaQuery.of(context).size.height,
                                  color: Colors.white.withOpacity(0.5),
                                  child: Center(
                                    child: SpinKitDualRing(
                                      color: Colors.pinkAccent,
                                      size: 45.0,
                                      controller: AnimationController(
                                        vsync: this,
                                        duration: const Duration(milliseconds: 1200),
                                      ),
                                    ),
                                  ),
                                )
                              ],
                            ))
        
      );
  }
//Go back coding
Future<bool> _goBack(BuildContext context) async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
      return Future.value(false);
    } else {
      showDialog(
          context: context,
          builder: (context) => AlertDialog(
                title: const Text('Do you want to exit from Foodrive?'),
                actions: <Widget>[
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    child: const Text('No'),
                  ),
                  TextButton(
                    onPressed: () {
                      SystemNavigator.pop();
                    },
                    child: const Text('Yes'),
                  ),
                ],
              ));
      return Future.value(true);
    }

  } 

}

Solution

  • I found a solution after paid someone for this answer. In this solution developer added 2 new packages import 'package:get/get.dart'; and import 'package:testing/pages/navigation_controller.dart';

    dependencies

    dependencies:
      flutter:
        sdk: flutter
      webview_flutter: ^2.3.0
      flutter_spinkit: ^5.1.0
      splash_screen_view: ^3.0.0
      flutter_icons: ^1.1.0
      pull_to_refresh: ^2.0.0 
      get:
    
     # The following adds the Cupertino Icons font to your application.
      # Use with the CupertinoIcons class for iOS style icons.
      cupertino_icons: ^1.0.4
    

    main.dart

    // ignore_for_file: prefer_const_constructors
    // ignore: use_key_in_widget_constructors
    import 'dart:io';
    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:get/get.dart';
    import 'package:testing/pages/navigation_controller.dart';
    import 'package:webview_flutter/webview_flutter.dart';
    import 'package:splash_screen_view/SplashScreenView.dart';
    import 'initial_bindings.dart';
    import 'pages/home_page.dart';
    import 'pages/profile.dart';
    import 'pages/cart.dart';
    
    void main() {
      SystemChrome.setSystemUIOverlayStyle(
          SystemUiOverlayStyle(statusBarColor: Color(0xff1e2229)));
    
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        Widget spalshfirst = SplashScreenView(
          navigateRoute: WebViewClass(),
          duration: 3000,
          imageSize: 80,
          imageSrc: 'assets/splash.png',
          text: "Food Delivery",
          textType: TextType.TyperAnimatedText,
          textStyle: TextStyle(
            fontSize: 25.0,
          ),
          colors: const [
            Colors.purple,
            Colors.blue,
            Colors.yellow,
            Colors.red,
          ],
          backgroundColor: Colors.white,
        );
        return GetMaterialApp(
            initialBinding: InitialBindings(),
            debugShowCheckedModeBanner: false,
            home: Scaffold(body: spalshfirst));
      }
    }
    
    class WebViewClass extends StatefulWidget {
      WebViewState createState() => WebViewState();
    }
    
    class WebViewState extends State<WebViewClass> with TickerProviderStateMixin {
      @override
      void initState() {
        super.initState();
        // Enable hybrid composition.
        if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
      }
    
      int currentIndex = 0;
      @override
      Widget build(BuildContext context) {
    //Including Dart Webview pages
        final screens = [
          HomeClass(),
          // Center(child: Text('refresh')),
          ProfileClass(),
          CartClass()
        ];
    
        return Scaffold(
          resizeToAvoidBottomInset: true,
          appBar: null,
          body: SafeArea(child: screens[currentIndex]),
          bottomNavigationBar: BottomNavigationBar(
            backgroundColor: Colors.pink,
            currentIndex: currentIndex,
            selectedItemColor: Colors.white,
            unselectedItemColor: Colors.white60,
            onTap: (index) {
              setState(() => currentIndex = index);
              Get.find<NavigationController>().controller.value?.reload();
            },
            items: const [
              BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.home),
                  label: 'Home',
                  backgroundColor: Colors.pink),
              // BottomNavigationBarItem(
              //     icon: Icon(CupertinoIcons.refresh),
              //     label: 'Refresh',
              //     backgroundColor: Colors.pink),
              BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.profile_circled),
                  label: 'Profile',
                  backgroundColor: Colors.red),
              BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.cart),
                  label: 'Cart',
                  backgroundColor: Colors.pink)
            ],
          ),
        );
      }
    }
    

    initial_bindings.dart

    import 'package:get/get.dart';
    import 'package:webview_flutter/webview_flutter.dart';
    
    class NavigationController extends GetxController {
      Rx<WebViewController?> controller = null.obs;
    }
    

    Home_page.dart same code for(profile.dart and cart.dart)

    import 'dart:async';
    import 'package:flutter/services.dart';
    import 'package:flutter_spinkit/flutter_spinkit.dart';
    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:pull_to_refresh/pull_to_refresh.dart';
    import 'package:testing/pages/navigation_controller.dart';
    import 'package:webview_flutter/webview_flutter.dart';
    
    class HomeClass extends StatefulWidget {
      Homestate createState() => Homestate();
    }
    
    class Homestate extends State<HomeClass> with TickerProviderStateMixin {
      late WebViewController _controller;
      final Completer<WebViewController> _controllerCompleter =
          Completer<WebViewController>();
    
      final RefreshController _refreshController =
          RefreshController(initialRefresh: false);
    
      late AnimationController animController;
    
      @override
      void initState() {
        super.initState();
        animController = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 1200),
        );
      }
    
      @override
      void dispose() {
        animController.dispose();
        super.dispose();
      }
    
      //Make sure this function return Future<bool> otherwise you will get an error
      Future<bool> _onWillPop(BuildContext context) async {
        if (await _controller.canGoBack()) {
          _controller.goBack();
          return Future.value(false);
        } else {
          return Future.value(true);
        }
      }
    
      bool isLoading = false;
      final key = UniqueKey();
      int position = 0;
    
      @override
      Widget build(BuildContext context) {
        return WillPopScope(
          onWillPop: () => _goBack(context),
          child: Scaffold(
            appBar: null,
            body: SmartRefresher(
              controller: _refreshController,
              enablePullDown: true,
              onRefresh: () {
                Get.find<NavigationController>().controller.value?.reload();
                _refreshController.refreshCompleted();
              },
              child: IndexedStack(
                index: position,
                children: [
                  WebView(
                    initialUrl: 'https://canada.ca',
                    javascriptMode: JavascriptMode.unrestricted,
                    key: key,
                    onPageStarted: (value) {
                      setState(() {
                        position = 1;
                      });
                    },
                    onPageFinished: (value) {
                      setState(() {
                        position = 0;
                      });
                    },
                    onWebViewCreated: (WebViewController webViewController) {
                      _controllerCompleter.future
                          .then((value) => _controller = value);
                      _controllerCompleter.complete(webViewController);
                      Get.find<NavigationController>().controller =
                          webViewController.obs;
                    },
                  ),
                  Container(
                    width: MediaQuery.of(context).size.width,
                    height: MediaQuery.of(context).size.height,
                    color: Colors.white.withOpacity(0.5),
                    child: Center(
                      child: SpinKitDualRing(
                        color: Colors.pinkAccent,
                        size: 45.0,
                        controller: animController,
                      ),
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      }
    
    //Go back coding
      Future<bool> _goBack(BuildContext context) async {
        if (await _controller.canGoBack()) {
          _controller.goBack();
          return Future.value(false);
        } else {
          showDialog(
              context: context,
              builder: (context) => AlertDialog(
                    title: const Text('Do you want to exit from Foodrive?'),
                    actions: <Widget>[
                      TextButton(
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                        child: const Text('No'),
                      ),
                      TextButton(
                        onPressed: () {
                          SystemNavigator.pop();
                        },
                        child: const Text('Yes'),
                      ),
                    ],
                  ));
          return Future.value(true);
        }
      }
    }