12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Flutter バックグラウンドで RefreshIndicator を消そうとすると消えずに残る

Last updated at Posted at 2018-03-19

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,
    @required this.child,
    this.displacement: 40.0,
    @required 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;
  
  @override
  State<StatefulWidget> createState() {
    return new MyRefreshIndicatorState();
  }
}

class MyRefreshIndicatorState extends State<MyRefreshIndicator> with WidgetsBindingObserver {
  Completer<Null> completer;
  bool foreground = true;
  
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }
  
  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
  
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    foreground = (state == AppLifecycleState.resumed);
    if (foreground && completer != null) {
      //debugPrint("complete on didChangeAppLifecycleState");
      completer.complete();
      completer = null;
    }
  }
  
  @override
  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 しています。これにより、アプリがフォアグラウンドにいるタイミングでインジケータを消す処理が行われ、期待通りに動作します。

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?