Flutter 上小部件的 onResume() 和 onPause()

问题描述 投票:0回答:7

目前,小部件只有在第一次创建小部件时触发的 initeState() 和在销毁小部件时触发的 dispose()。有没有一种方法可以检测小部件何时返回前台?当一个小部件因为另一个小部件刚刚在前台而即将进入后台时? 相当于 Android 上触发 onResume 和 onPause,ios 上触发 viewWillAppear 和 viewWillDisappear

android ios dart lifecycle flutter
7个回答
56
投票

有一个抽象类调用者WidgetsBindingObserver

https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    setState(() {
            _notification = state;
    });
  }

有“状态”,可以管理为

switch(state) {
  case AppLifecycleState.resumed:
    // Handle this case
    break;
  case AppLifecycleState.inactive:
    // Handle this case
    break;
  case AppLifecycleState.paused:
    // Handle this case
    break;
  case AppLifecycleState.suspending:
    // Handle this case
    break;
}

40
投票

这是一个完整的示例,演示了如何正确处理事情,要测试这一点,请按主页按钮并恢复应用程序,您将看到

didChangeAppLifecycleState
正在被调用。

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();

    // Add the observer. 
    WidgetsBinding.instance!.addObserver(this);
  }

  @override
  void dispose() {
    // Remove the observer
    WidgetsBinding.instance!.removeObserver(this);

    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);

    // These are the callbacks
    switch (state) {
      case AppLifecycleState.resumed:
        // widget is resumed
        break;
      case AppLifecycleState.inactive:
        // widget is inactive
        break;
      case AppLifecycleState.paused:
        // widget is paused
        break;
      case AppLifecycleState.detached:
        // widget is detached
        break;
    }
  }

  @override
  Widget build(BuildContext context) => Scaffold();
}

17
投票

您想要执行此操作的最常见情况是,如果您正在运行动画并且您不想在后台消耗资源。在这种情况下,您应该使用

State
扩展
TickerProviderStateMixin
并使用
State
作为
vsync
AnimationController
参数。仅当您的
State
可见时,Flutter 才会负责调用动画控制器的侦听器。

如果您希望在

State
被其他内容遮挡时处理
PageRoute
中的
PageRoute
,您可以将 maintainState
false
 参数传递给 
PageRoute
构造函数。如果这样做,您的
State
将在隐藏时重置自身(及其子级),并且必须使用作为构造函数参数传递给其
initState
的属性在
widget
中重新构造自身。如果您不想完全重置,可以使用模型或控制器类,或
PageStorage
来保存用户的进度信息。

这是一个演示这些概念的示例应用程序。

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    onGenerateRoute: (RouteSettings settings) {
      if (settings.name == '/') {
        return new MaterialPageRoute<Null>(
          settings: settings,
          builder: (_) => new MyApp(),
          maintainState: false,
        );
      }
      return null;
    }
  ));
}

class MyApp extends StatefulWidget {
  MyAppState createState() => new MyAppState();
}

class MyAppState extends State<MyApp> with TickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    print("initState was called");
    _controller = new AnimationController(vsync: this)
      ..repeat(min: 0.0, max: 1.0, period: const Duration(seconds: 1))
      ..addListener(() {
        print('animation value ${_controller.value}');
      });
    super.initState();
  }

  @override
  void dispose() {
    print("dispose was called");
    _controller.dispose();
    super.dispose();
  }

  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('home screen')
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
          child: new Text('Button pressed $_counter times'),
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.remove_red_eye),
        onPressed: () {
          Navigator.push(context, new MaterialPageRoute(
            builder: (BuildContext context) {
              return new MySecondPage(counter: _counter);
            },
          ));
        },
      ),
    );
  }
}

class MySecondPage extends StatelessWidget {
  MySecondPage({ this.counter });

  final int counter;

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Certificate of achievement'),
      ),
      body: new Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          new Icon(Icons.developer_mode, size: 200.0),
          new Text(
            'Congrats, you clicked $counter times.',
            style: Theme.of(context).textTheme.title,
            textAlign: TextAlign.center,
          ),
          new Text(
            'All your progress has now been lost.',
            style: Theme.of(context).textTheme.subhead,
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }
}

13
投票

我有点晚了,但为那些将来可能正在寻找它的人提供了完美的解决方案。

Navigator.push()
实际上是一个Future。这意味着它有
then()
回调函数。因此,当您从第二个屏幕调用
then()
后,将会调用
Navigator.pop()
。甚至您可以从第二个屏幕发送一些数据并访问第一个屏幕中的数据。

示例:

//from Screen A
Navigator.of(context).push(MaterialPageRoute(builder:(context)=>B()))
.then((value)=>{ refresh() });

//in Screen B with data
Navigator.pop(context,[1]);

//or without data
Navigator.pop(context);

所以

refresh()
将在屏幕 A 的恢复中被调用。


8
投票

我创建了 visibility_aware_state,其行为类似于 Android 的

Activity.onResume()
。它还考虑了弹出和推送导航。

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends VisibilityAwareState<Example> {
  @override
  Widget build(BuildContext context) {
    // return your widget
  }

  @override
  void onVisibilityChanged(WidgetVisibility visibility) {
    switch(visibility) {
      case WidgetVisibility.VISIBLE:
        // Like Android's Activity.onResume()
        break;
      case WidgetVisibility.INVISIBLE:
        // Like Android's Activity.onPause()
        break;
      case WidgetVisibility.GONE:
        // Like Android's Activity.onDestroy()
        break;
    }
    super.onVisibilityChanged(visibility);
  }
}

3
投票

Mamnarock您的答案是正确的但不完整,并且您共享的链接不可用。

完整代码如下:

import 'package:flutter/material.dart';

class YourClass extends StatefulWidget {

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

class _YourClassState extends State<YourClass>
    with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        // Handle this case
        break;
      case AppLifecycleState.inactive:
        // Handle this case
        break;
      case AppLifecycleState.paused:
        // Handle this case
        break;
      case AppLifecycleState.detached:
        // Handle this case
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

正如 TeeTracker 在评论中提到的:

这是应用程序级别的生命周期,这意味着当整个组件恢复或不活动或暂停时,而不是单个小部件。


0
投票

如果您安装了Flutter Hookshttps://pub.dev/packages/flutter_hooks):

@override
Widget build(BuildContext context) {
  useOnAppLifecycleStateChange((previous, current) => null);
}
© www.soinside.com 2019 - 2024. All rights reserved.