Flutter Web画面表示（進捗バー付き）

Flutterで、進捗バー付きのWeb画面表示を実装しました。

# 環境

- Flutter 2.8.1
- Dart 2.15.0

# Package

Web画面表示の方法はいくつかあると思いますが、
今回は、[webview_flutter](https://pub.dev/packages/webview_flutter)を使用しました。

```pubspec.yaml
webview_flutter: ^3.0.0　# 追加
```
# 完成形

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1519965/48fbfc58-41f4-0e98-c6f3-c98ea6323b3a.gif)

# 実装

初めの画面

```main.dart
void main() {
  runApp(
    const MyApp(),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const HomeScreen(),
      routes: {
        // Web画面のルーティング
        WebViewScreen.routeName: (context) => const WebViewScreen(),
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          child: const Text('Press'),
          onPressed: () {
            // Web画面へ遷移
            Navigator.pushNamed(context, WebViewScreen.routeName);
          },
        ),
      ),
    );
  }
}

〜〜〜
続く
〜〜〜
```
Web画面

```main.dart

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

  static const String routeName = '/web-view';

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

class _WebViewScreenState extends State<WebViewScreen> {
  final _key = UniqueKey();
  final Completer<WebViewController> _controller = Completer<WebViewController>();
  bool _isLoading = true; // ローディングの有無
  String _title = ''; // Webタイトル
  double _downloadPercentage = 0.0; // 進捗バー用

  @override
  void initState() {
    super.initState();
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }

  // ローディングの切り替え
  void toggleLoading() {
    setState(() {
      _isLoading = !_isLoading;
    });
  }

  // 進捗計算
  void calculateProgress(int progress) {
    setState(() {
      _downloadPercentage = (progress / 100);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_title),// Web画面のタイトルを表示
      ),
      body: Column(
        children: [
          // 進捗バー
          _isLoading ? LinearProgressIndicator(value: _downloadPercentage, minHeight: 7.0,) : const SizedBox.shrink(),
          Expanded(
            child: Scrollbar(
              showTrackOnHover: true,
              child: WebView(
                key: _key,
                initialUrl: 'https://qiita.com/',
                javascriptMode: JavascriptMode.unrestricted,
                onWebViewCreated: _controller.complete,
                onPageFinished: (String url) async {
                  if (_isLoading) toggleLoading();
                  final controller = await _controller.future;
                  final title = await controller.getTitle();
                  if (title != null) _title = title;
                },
                onProgress: (progress) {
                  calculateProgress(progress);
                }
              ),
            ),
          ),
        ],
      ),
    );
  }
}
```

Web画面が完全に読み込まれるまで、onProgressで読み込みの計算をします。

```
onProgress: (progress) {
　　calculateProgress(progress);
}
```

その計算した値を`LinearProgressIndicator`のvalueに渡せば進捗の表示ができます。

```
LinearProgressIndicator(value: _downloadPercentage)
```

`onPageFinished`では読み込まれた後の処理を記述
`_isLoading `のローディングの非表示へ切り替え
`controller`でWebに設定されているタイトルを取得し、変数に代入すればOKです。

```
onPageFinished: (String url) async {
  if (_isLoading) toggleLoading();
  final controller = await _controller.future;
  final title = await controller.getTitle();
  if (title != null) _title = title;
},
```