Spicier Ewe
Spicier Ewe

Reputation: 15

inAppWebview controller not working with IndexedStack

the controller is not working as it should i'm dynamically generating 3 webviews in stackedIndex , what the controller is doing that it is only working on the last website in stackedIndex.

all the controller events are working normally and only when i interact with the last website. you can reproduce the same result using the code below.

The usage of IndexedStack is important here in order to prevent page from reloading when switch between webpages and also to maintain state of the webpages.

Here is the code ~


import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

class ShowItems extends StatefulWidget {
const ShowItems({Key? key}) : super(key: key);

@override
State<ShowItems> createState() => _ShowItemsState();
}

class _ShowItemsState extends State<ShowItems> {

List services = [
{
  'service_name': 'expample1',
  'website_link': 'https://www.example1.com/',
  'icon': const Icon(Icons.location),
  'color': const Color(0xffE23744)
},
{
  'service_name': 'expample2',
  'website_link': 'https://www.expample2.com/',
  'icon': const Icon(Icons.location_on),
  'color': const Color(0xfff18423)
},
{
  'service_name': 'expample3',
  'website_link':
      'https://www.expample3.com/',
  'icon': const Icon(Icons.location),
  'color': const Color(0xff801A00)
},
];
}

InAppWebViewController? webViewController;
int _currentIndex = 0;


final pageController = PageController();

void onPageChanged(int index) {
setState(() {
  _currentIndex = index;
});
}

@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
return WillPopScope(
  onWillPop: () async {
    // print(await webViewController.canGoBack());
    // print(await webViewController.currentUrl());
    if (await webViewController?.canGoBack() == true) {
      webViewController?.goBack();
      return false;
    }

    return false;
  },
  child: LayoutBuilder(
    builder: (context, constraints) {
      final cmh = constraints.maxHeight;
      final cmw = constraints.maxWidth;
      return Scaffold(
        appBar: AppBar(
          backgroundColor: services[_currentIndex]
              ['color'],
          elevation: 0,
          title: Text(
              services[_currentIndex]['service_name']),

          ///here is the settings icon
          actions: [
            IconButton(
              onPressed: () {
                Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => const SettingsScreen(),
                    ));
              },
              icon: const Icon(Icons.settings),
              splashRadius: cmh * 0.021,
            )
          ],
        ),
        body: IndexedStack(
          index: _currentIndex,
          // physics: const NeverScrollableScrollPhysics(),
          children: [
            for (int x = 0; x < services.length; x++)
              InAppWebView(
                // key: webViewKey,
                initialUrlRequest: URLRequest(
                    url: Uri.parse(
                        services[x]['website_link'])),
                onWebViewCreated: (controller) {
                  webViewController = controller;
                },
                initialOptions: InAppWebViewGroupOptions(
                  android: AndroidInAppWebViewOptions(
                    allowContentAccess: true,
                    builtInZoomControls: true,
                    thirdPartyCookiesEnabled: true,
                    allowFileAccess: true,
                    geolocationEnabled: true,
                    supportMultipleWindows: true,
                  ),
                  crossPlatform: InAppWebViewOptions(
                    useShouldOverrideUrlLoading: true,
                    useOnDownloadStart: true,
                    allowFileAccessFromFileURLs: true,
                    allowUniversalAccessFromFileURLs: true,
                  ),
                ),
              ),
          ],
          // controller: pageController,
          // onPageChanged: onPageChanged,
        ),
        bottomNavigationBar: BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          selectedIconTheme: IconThemeData(
              color: services[_currentIndex]
                      ['color'] ??
                  Colors.amber),
          selectedItemColor: services[_currentIndex]
                  ['color'] ??
              Colors.amber,

          // unselectedIconTheme: IconThemeData(opacity: 0.0, size: 0),
          currentIndex: _currentIndex,
          items: [
            for (int i = 0; i < services.length; i++)
              BottomNavigationBarItem(
                label: services[i]['service_name'],
                icon: services[i]['icon'],
              ),
          ],
          onTap: (int index) {
            setState(() {
              _currentIndex = index;
            });
      
          },
        ),
      );
    },
  ),
);
}
}

Upvotes: 0

Views: 1122

Answers (1)

Kaushik Chandru
Kaushik Chandru

Reputation: 17812

Since you have only 1 web view controller and on each webview page creation it's re assigned and only the last webview's controller will stay. Either when you charge the index reassign the controller or add 3 different controllers

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List services = [
    {
      'service_name': 'expample1',
      'website_link': 'https://www.example1.com/',
      'icon': Icon(Icons.location_city),
      'color': const Color(0xffE23744)
    },
    {
      'service_name': 'expample2',
      'website_link': 'https://google.com/',
      'icon': const Icon(Icons.location_on),
      'color': const Color(0xfff18423)
    },
    {
      'service_name': 'expample3',
      'website_link': 'https://www.wikipedia.com/',
      'icon': const Icon(Icons.location_city),
      'color': const Color(0xff801A00)
    },
  ];
  late List<InAppWebViewController> inAppWebViewControllers;
  int _currentIndex = 0;

  final pageController = PageController();

  void onPageChanged(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

  Widget build(BuildContext context) {
    inAppWebViewControllers = [];

    return Scaffold(
        body: WillPopScope(
            onWillPop: () async {
              print("hi");
              if (await inAppWebViewControllers[_currentIndex].canGoBack() ==
                  true) {
                inAppWebViewControllers[_currentIndex].goBack();
                return false;
              }

              return false;
            },
            child: Container(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height,
                child: LayoutBuilder(builder: (context, constraints) {
                  final cmh = constraints.maxHeight;
                  final cmw = constraints.maxWidth;
                  return Scaffold(
                    appBar: AppBar(
                      backgroundColor: services[_currentIndex]['color'],
                      elevation: 0,
                      title: Text(services[_currentIndex]['service_name']),

                      ///here is the settings icon
                      actions: [
                        IconButton(
                          onPressed: () {
                            // Navigator.push(
                            //     context,
                            //     MaterialPageRoute(
                            //       builder: (context) => const SettingsScreen(),
                            //     ));
                          },
                          icon: const Icon(Icons.settings),
                          splashRadius: cmh * 0.021,
                        )
                      ],
                    ),
                    body: SafeArea(
                      child: Column(
                        // index: _currentIndex,
                        // physics: const NeverScrollableScrollPhysics(),
                        children: List.generate(
                            services.length,
                            (x) => CustomWebPage(
                                controllerList: inAppWebViewControllers,
                                currentIndex: _currentIndex,
                                x: x,
                                services: services)),
                        // controller: pageController,
                        // onPageChanged: onPageChanged,
                      ),
                    ),
                    bottomNavigationBar: BottomNavigationBar(
                      type: BottomNavigationBarType.fixed,
                      selectedIconTheme: IconThemeData(
                          color:
                              services[_currentIndex]['color'] ?? Colors.amber),
                      selectedItemColor:
                          services[_currentIndex]['color'] ?? Colors.amber,

                      // unselectedIconTheme: IconThemeData(opacity: 0.0, size: 0),
                      currentIndex: _currentIndex,
                      items: [
                        for (int i = 0; i < services.length; i++)
                          BottomNavigationBarItem(
                            label: services[i]['service_name'],
                            icon: services[i]['icon'],
                          ),
                      ],
                      onTap: (int index) {
                        setState(() {
                          _currentIndex = index;
                        });
                      },
                    ),
                  );
                }))));
  }
}

class CustomWebPage extends StatelessWidget {
  final int currentIndex;
  final int x;
  final List services;
  final List<InAppWebViewController> controllerList;
  const CustomWebPage(
      {Key? key,
      required this.currentIndex,
      required this.x,
      required this.services,
      required this.controllerList})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    InAppWebViewController? webViewController;

    return Offstage(
      offstage: currentIndex != x,
      child: Container(
        height: MediaQuery.of(context).size.height - 200,
        width: MediaQuery.of(context).size.width,
        child: InAppWebView(
          // key: webViewKey,
          initialUrlRequest:
              URLRequest(url: Uri.parse(services[x]['website_link'])),
          onWebViewCreated: (controller) {
            controllerList.insert(currentIndex, controller);
          },
          initialOptions: InAppWebViewGroupOptions(
            android: AndroidInAppWebViewOptions(
              allowContentAccess: true,
              builtInZoomControls: true,
              thirdPartyCookiesEnabled: true,
              allowFileAccess: true,
              geolocationEnabled: true,
              supportMultipleWindows: true,
            ),
            crossPlatform: InAppWebViewOptions(
              useShouldOverrideUrlLoading: true,
              useOnDownloadStart: true,
              allowFileAccessFromFileURLs: true,
              allowUniversalAccessFromFileURLs: true,
            ),
          ),
        ),
      ),
    );
  }
}

Upvotes: 1

Related Questions