👻
Flutter バックグラウンドで RefreshIndicator を消そうとすると消えずに残る
Flutter でいわゆる「引っ張って更新」の機能を提供してくれる RefreshIndicator という Widget があります。
onRefresh
で更新の処理を行い、その Future
が完了するとインジケータが非表示になります。
ところが、この Future
が完了したタイミングでアプリがバックグラウンドにいると、アプリがフォアグラウンドに戻った時にも、インジケータが消えずに残ったままとなります。
Issue として報告済み: https://github.com/flutter/flutter/issues/14619
ワークアラウンドとして、以下のような RefreshIndicator
をラップした Widget を作りました。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
class MyRefreshIndicator extends StatefulWidget {
const MyRefreshIndicator({
Key key,
this.child,
this.displacement: 40.0,
this.onRefresh,
this.color,
this.backgroundColor,
this.notificationPredicate: defaultScrollNotificationPredicate,
}) : assert(child != null),
assert(onRefresh != null),
assert(notificationPredicate != null),
super(key: key);
final Widget child;
final double displacement;
final RefreshCallback onRefresh;
final Color color;
final Color backgroundColor;
final ScrollNotificationPredicate notificationPredicate;
State<StatefulWidget> createState() {
return new MyRefreshIndicatorState();
}
}
class MyRefreshIndicatorState extends State<MyRefreshIndicator> with WidgetsBindingObserver {
Completer<Null> completer;
bool foreground = true;
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
void didChangeAppLifecycleState(AppLifecycleState state) {
foreground = (state == AppLifecycleState.resumed);
if (foreground && completer != null) {
//debugPrint("complete on didChangeAppLifecycleState");
completer.complete();
completer = null;
}
}
Widget build(BuildContext context) {
return new RefreshIndicator(
child: widget.child,
onRefresh: _onRefresh,
displacement: widget.displacement,
color: widget.color,
backgroundColor: widget.backgroundColor,
notificationPredicate: widget.notificationPredicate,
);
}
Future<Null> _onRefresh() {
final Completer<Null> completer = new Completer<Null>();
widget.onRefresh().then((_) {
if (foreground) {
//debugPrint("complete on original future");
completer.complete();
} else {
this.completer = completer;
}
});
return completer.future;
}
}
ポイントとしては、実際の処理の Future
が完了したタイミングで、アプリがフォアグラウンドにいるかどうか確認して、いないのであれば complete
せずに待っておき、フォアグラウンドになった時点で complete
しています。これにより、アプリがフォアグラウンドにいるタイミングでインジケータを消す処理が行われ、期待通りに動作します。
この記事はQiitaの記事をエクスポートしたものです
Discussion