如何检查我的小部件屏幕何时像在Android中的onResume一样颤动可见

时间:2019-09-09 14:57:08

标签: android flutter

在android中,如果可见活动,则调用onResume。 {strong> Flutter 中onResume的等效方法是什么?

我需要知道何时可以看到小部件屏幕,以便基于此自动播放视频。我可能会转到另一个窗口小部件屏幕,当我回来时它将自动播放。

我的方法是在didUpdateWidget中播放视频,但是即使看不到窗口小部件屏幕,每次也会调用didUpdateWidget

注意:我并不是从didChangeAppLifecycleState询问WidgetsBindingObserver,因为它为应用程序生命周期提供了onResume等回调,而不是特定的窗口小部件屏幕。

4 个答案:

答案 0 :(得分:5)

在不查看应用主屏幕时,我很难使视频暂停。我应用了此VisibilityDetector,然后抓住visiblePercentage来强制暂停或继续:

VisibilityDetector(
    key: Key('visible-video--key-${this.randomkeygenerator}-1'),
    onVisibilityChanged: (visibilityInfo) {
      var visiblePercentage = visibilityInfo.visibleFraction * 100;

      if (visiblePercentage < 1){ //the magic is done here
        if(_video_controller != null) {
          if(disposed_vid == false) {
            _video_controller.pause();
          }
        }

      }else{
        if(_video_controller != null) {
          if(disposed_vid == false) {
            _video_controller.play();
          }
        }
      }
      debugPrint(
          'Widget ${visibilityInfo.key} is ${visiblePercentage}% visible');
    },
    child: VideoPlayer(_video_controller)),


  @override
  void dispose() {
    // If the video is playing, pause it.
    _video_controller .pause();
    _video_controller .dispose();
    disposed_vid = true;
    super.dispose();
  }

答案 1 :(得分:3)

所有问题都解决了。

从小部件树(materialappwidget)的根目录在导航器上放置一个观察者。

如果您需要更多说明,请点击此链接: https://api.flutter.dev/flutter/widgets/RouteObserver-class.html

我已经在我的项目中实现了它,并且它的@ Sp4Rx效果很好

// Register the RouteObserver as a navigation observer.
final RouteObserver<PageRoute> routeObserver = 
  RouteObserver<PageRoute>();
  void main() {
runApp(MaterialApp(
home: Container(),
navigatorObservers: [routeObserver],
 ));
   }

 class RouteAwareWidget extends StatefulWidget {
  State<RouteAwareWidget> createState() => RouteAwareWidgetState();
 }

 // Implement RouteAware in a widget's state and subscribe it to 
  the 
  RouteObserver.
  class RouteAwareWidgetState extends State<RouteAwareWidget> with 
 RouteAware {

@override
void didChangeDependencies() {
  super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context));
}

@override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}

@override
void didPush() {
  // Route was pushed onto navigator and is now topmost route.
}

 @override
void didPopNext() {
  // Covering route was popped off the navigator.
 }

@override
Widget build(BuildContext context) => Container();

 } 

答案 2 :(得分:1)

这可能不是最简单的,而且绝对不是完美的,但不久前我实现了带有路线的事件。基本上,EventRoute<T>MaterialPageRoute<T>的替代品,它为创建Widget,将其推到前台,推到后台以及当它弹出时提供可选的回调。

event_route.dart

import 'package:flutter/material.dart';

enum RouteState {
  none,
  created,
  foreground,
  background,
  destroyed
}

class EventRoute<T> extends MaterialPageRoute<T> {
  BuildContext _context;
  RouteState _state;
  Function(BuildContext) _onCreateCallback;
  Function(BuildContext) _onForegroundCallback;
  Function(BuildContext) _onBackgroundCallback;
  Function(BuildContext) _onDestroyCallback;

  EventRoute(BuildContext context, {
    builder,
    RouteSettings settings,
    bool maintainState = true,
    bool fullscreenDialog = false,
    Function(BuildContext) onCreate,
    Function(BuildContext) onForeground,
    Function(BuildContext) onBackground,
    Function(BuildContext) onDestroy
  }):
        _context = context,
        _onCreateCallback = onCreate,
        _onForegroundCallback = onForeground,
        _onBackgroundCallback = onBackground,
        _onDestroyCallback = onDestroy,
        _state = RouteState.none,
        super(builder: builder, settings: settings, maintainState: maintainState, fullscreenDialog: fullscreenDialog);


  void get state => _state;

  @override
  void didChangeNext(Route nextRoute) {
    if (nextRoute == null) {
      _onForeground();
    } else {
      _onBackground();
    }
    super.didChangeNext(nextRoute);
  }

  @override
  bool didPop(T result) {
    _onDestroy();
    return super.didPop(result);
  }

  @override
  void didPopNext(Route nextRoute) {
    _onForeground();
    super.didPopNext(nextRoute);
  }

  @override
  TickerFuture didPush() {
    _onCreate();
    return super.didPush();
  }

  @override
  void didReplace(Route oldRoute) {
    _onForeground();
    super.didReplace(oldRoute);
  }

  void _onCreate() {
    if (_state != RouteState.none || _onCreateCallback == null) {
      return;
    }
    _onCreateCallback(_context);
  }

  void _onForeground() {
    if (_state == RouteState.foreground) {
      return;
    }
    _state = RouteState.foreground;
    if (_onForegroundCallback != null) {
      _onForegroundCallback(_context);
    }
  }

  void _onBackground() {
    if (_state == RouteState.background) {
      return;
    }
    _state = RouteState.background;
    if (_onBackgroundCallback != null) {
      _onBackgroundCallback(_context);
    }
  }

  void _onDestroy() {
    if (_state == RouteState.destroyed || _onDestroyCallback == null) {
      return;
    }
    _onDestroyCallback(_context);
  }
}

然后按照您的路线行事:

Navigator.push(context, EventRoute(context, builder: (context) => YourWidget(context),
      onCreate: (context) => print('create'),
      onForeground: (context) => print('foreground'),
      onBackground: (context) => print('background'),
      onDestroy: (context) => print('destroy')
));

尽管上下文有点棘手...

答案 3 :(得分:0)

因为后台路由的动画会被禁用。所以我们可以这样判断是否在前台:

final isForeground = TickerMode.of(context);

将它包装成一个小部件:

/// Created by ipcjs on 2021/3/23.
class ForegroundDetector extends StatefulWidget {
  const ForegroundDetector({
    Key? key,
    required this.child,
    required this.onForegroundChanged,
  }) : super(key: key);

  final ValueChanged<bool> onForegroundChanged;
  final Widget child;

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

class ForegroundDetectorState extends State<ForegroundDetector> {
  bool get isForeground => _isForeground ?? false;
  bool? _isForeground;

  @override
  Widget build(BuildContext context) {
    final isForeground = TickerMode.of(context);
    if (_isForeground != isForeground) {
      _isForeground = isForeground;
      widget.onForegroundChanged(isForeground);
    }
    return widget.child;
  }
}