FlutterのBottomNavigationBarでWebViewが複数作れない問題
起きた問題
AndroidのBottomNavigationBarでは画面とItem内の画面が1:1になっていると思うのですが、FlutterでWebViewを使う場合に1:1にできないという問題が起きました。解決策他にあればコメントなどでいただけたらと🙏
どういうこと?
-
AndroidのネイティブBottomNavigationBar、iOSのネイティブTabBarControllerは基本的にメニューに対して画面が 1:1になる。
-
Flutterも基本はそう。
-
FlutterのWebViewだと1:1にするとメニューを切り替えた際に新しいWebViewが生成されないため、BottomNavigationBarのメニューが多、WebViewが1にしないとWebViewの読み込みができなくなるため、1:多 構造にしないといけない。
図にすると
Androidネイティブのイメージ
Flutterのイメージ
どうなるのか
BottomNavigationBarItemのindex番号に応じてリストで作ったURLを取得してloadし直す。
URLの定義
リストでBottomNavigationBarのindex準に定義しておく、またはMap<int, String>で作っておく。
List<String> _urlList = [
'https://www.google.com/',
'https://www.yahoo.co.jp/',
'https://qiita.com/'
];
呼び出し側
FlutterのBottomNavigationBarはItemのタップ時にindex番号が返ってくるのでBottomNavigationBarのタップを拾うイベントでWebViewControllerのloadUrlを呼ぶ形になる。
_webViewController.loadUrl(_urlList[index]);
挙動を考える
iOSのTabBarControllerの場合は、タブA内で遷移が発生してからタブBに切り替えて、再度タブAに切り替えても前のタブの情報が残っている。今いるタブをタップするとそのタブ内で遷移していた場合一つ戻る。
AndroidのBottomNavigationBarの場合はタブA内で遷移が発生してからタブBに切り替えて、再度タブAに切り替えた場合タブAのトップの画面に戻る。今いるタブをタップするとそのタブ内のトップの画面に戻る。
SDK33あたりで挙動がiOSと同じになっている気がする。
Flutterの場合も基本的にはマテリアルデザインなので同じ挙動。なのでWebViewが1:多でもタブ切り替え時にタブのトップのページに戻っていいので問題がないが、iOSらしい挙動に調整しようとすると現状不可かもしれない。もしくは挙動を結構いじることになるので気をつけた方がよさそう。
Discussion
試したことはないですが、
以下の人は、WebViewWidgetに一意なkeyを与えるとちゃんと動いた的なこと言ってます。
controllerはタブ毎に生成されていますでしょうか?
WebViewというより、Controllerが変わってないからWebViewが切り替わらないのかなーとか思いました。。
また、以下のライブラリや
go_routerのStatefulShellRouteなど使うと、ios風が作れると思います! (個人的には、go_routerを使うほうが良いかなと思います)
ありがとうございます!
ちょっと前のコードだったのでgo_routerみたいなものは使ってなかったのですが、Controllerを各タブごとに作るというのはしてなかったですね・・・。
WebViewに対して1対1だと思ってたので、WebViewが1つなのがそもそもの問題?
ios風BottomNavigation書かれてる方いました!参考にいたします!
タブ毎にWebViewとcontrollerを作るとAndroid風になるかなと思います。
強いて言うなら、
タブバーで取得したindexから、urlを取得するのではなく、widgetを取ってきて描画した方が良いかなと思います!
そのwidgetの中でWebViewとcontroller作ると上手くいくのかなーと思います。