前回まではこちら
repository:
前回の続きで記事をWebViewに表示させるところからやります
pluginのwebview_flutterというものがあり、こちらを導入します。
またこちらはcodelabもあったのですが, 3.x系の内容で現在の4.x系ではなかったのでREADMEを読みながら導入していきたいと思います
webview_flutter
まずは以下コマンドで追加
flutter pub add webview_flutter
追加したらios/androidのMinimumOSVersion/minSdkVersion
を確認する
webview_flutterの現在の最新(4.0.6)ではiosは11以上、androidは19以上が必須になっているので必要であれば更新する
まずはios
該当箇所はios/Flutter/AppFrameworkInfo.plist
の中のMinimumOSVersion
このアプリの場合は11.0になっていたので特に変更なくこのまま
続いてandroid
該当箇所はandroid/app/build.gradle
のminSdkVersion
flutter.minSdkVersion
となっている。具体的な値は何になっているのだろうか
local.properties
の中身を確認しても定義されていない。分からなかったので無難に20に変更
flutterのsdk側で定義されてるのかな?
とりあえずこれで使えるようになったはず
README通りcontroller
を定義してWebViewWidget
に渡す
以下の感じになった
class ArticleWebView extends StatelessWidget {
const ArticleWebView({super.key});
static const routeName = '/article';
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as ArticleArguments;
final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadRequest(Uri.parse(args.url));
return Scaffold(
appBar: AppBar(
title: Text('article'),
),
body: WebViewWidget(controller: controller),
);
}
}
必要最小限だとこんな感じですかね
表示は出来ましたが、もう少しwebviewを触ってみます
表示までに読み込みが結構かかります。progressを出したい
CircularProgressIndicator
とLinearProgressIndicator
などが検索すると出てきました
WebViewなのでLinearProgressIndicator
の方がっぽい気がするのでこちらを採用します
webviewのREADMEにあったonProgress
が使えそうなので試してみる
controllerに追加してどのような値が入ってくるのか確認します
..setNavigationDelegate(NavigationDelegate(
onProgress: (int progress) {
print(progress);
},
))
実行しwebviewを開くと以下のログが
flutter: 10
flutter: 30
flutter: 48
flutter: 89
flutter: 90
flutter: 90
flutter: 90
flutter: 90
flutter: 90
flutter: 90
flutter: 100
やはりLoadingの進捗度合いが取れそうなのでこれを使う
またこのwebviewを使ってるwidgetがstatelessなのでstatefulに変更する
class ArticleWebView extends StatefulWidget {
const ArticleWebView({super.key});
static const routeName = '/article';
@override
State<ArticleWebView> createState() => _ArticleWebView();
}
class _ArticleWebView extends State<ArticleWebView> {
int _progress = 0;
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as ArticleArguments;
final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onProgress: (int progress) {
print(progress);
_progress = progress;
},
onPageStarted: (url) {
print('start');
},
onPageFinished: (url) {
print('finish');
},
))
..loadRequest(Uri.parse(args.url));
return Scaffold(
appBar: AppBar(
title: Text('article'),
),
body: Column(
children: [
LinearProgressIndicator(value: _progress.toDouble()),
Expanded(child: WebViewWidget(controller: controller)),
],
));
}
}
これで実行してみる
あれ?終わらない...
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: start
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: start
flutter: 10
flutter: 10
flutter: start
flutter: 10
flutter: 10
flutter: 30
flutter: 30
flutter: 10
flutter: 10
flutter: 10
flutter: 10
flutter: 30
flutter: 10
flutter: 10
flutter: 10
flutter: start
flutter: 10
flutter: 10
flutter: start
flutter: 10
flutter: 10
flutter: start
flutter: start
flutter: 10
flutter: 10
flutter: start
flutter: start
flutter: start
flutter: 10
flutter: start
flutter: 10
flutter: 46
flutter: 86
flutter: 10
...
build
の中でcontroller
を定義しているから_progress
の値が変わる度にbuild
が呼ばれてcontroller
が定義され直して?終わらない感じっぽい
困った。urlは引数として前の画面から受け取らないとなのでbuild
の中で定義してたのだが分割しよう
試行錯誤で出来たコードが以下
class ArticleWebView extends StatefulWidget {
const ArticleWebView({super.key});
static const routeName = '/article';
@override
State<ArticleWebView> createState() => _ArticleWebView();
}
class _ArticleWebView extends State<ArticleWebView> {
double _progress = 0.0;
bool _isFirst = true;
bool _isLoading = false;
final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted);
@override
void initState() {
super.initState();
controller.setNavigationDelegate(NavigationDelegate(
onPageStarted: (url) {
if (mounted) {
setState(() {
_isLoading = true;
});
}
},
onPageFinished: (url) {
if (mounted) {
setState(() {
_isLoading = false;
});
}
},
onProgress: (progress) {
if (mounted) {
setState(() {
_progress = progress / 100;
});
}
},
));
}
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as ArticleArguments;
if (_isFirst) {
_isFirst = false;
controller.loadRequest(Uri.parse(args.url));
}
return Scaffold(
appBar: AppBar(
title: const Text('article'),
),
body: Column(
children: [
_isLoading
? LinearProgressIndicator(value: _progress)
: const SizedBox.shrink(),
Expanded(child: WebViewWidget(controller: controller)),
],
),
);
}
}
ほ、本当に?_isFirst
とかいつの時代だよとPRに書かれそう
これどうするのが正解なのか有識者の方教えてください。お願いします
まあでもとりあえず動いたから良し
なんか軽い気持ちでProgress出したかったのに意外と大変だった。多分知らないだけなんだろうけど。
今回はここまで。後何をやろう...ページング対応してないか
次回はページングやろうと思います