Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何检查我的widget屏幕在Android中的flutter-like-onResume中何时可见_Android_Flutter - Fatal编程技术网

如何检查我的widget屏幕在Android中的flutter-like-onResume中何时可见

如何检查我的widget屏幕在Android中的flutter-like-onResume中何时可见,android,flutter,Android,Flutter,在android中,如果某个活动在恢复时可见,则调用onResume。在颤振中,恢复的等效方法是什么 我需要知道什么时候我的小部件屏幕是可见的,这样我就可以自动播放视频的基础上。当我回来时,我可能会转到另一个小部件屏幕,它会自动播放 我的方法是在didUpdateWidget中播放视频,但是每次小部件屏幕不可见时都会调用didUpdateWidget 注意:我不是在问WidgetsBindingObserver中的didchangeApplicyclestate问题,因为它为应用程序生命周期而不

在android中,如果某个活动在恢复时可见,则调用
onResume
。在颤振中,恢复的等效方法是什么

我需要知道什么时候我的小部件屏幕是可见的,这样我就可以自动播放视频的基础上。当我回来时,我可能会转到另一个小部件屏幕,它会自动播放

我的方法是在
didUpdateWidget
中播放视频,但是每次小部件屏幕不可见时都会调用
didUpdateWidget


注意:我不是在问
WidgetsBindingObserver
中的
didchangeApplicyclestate
问题,因为它为应用程序生命周期而不是特定的小部件屏幕提供
onResume
etc回调

这可能不是最简单的,也绝对不是完美的,但不久前我实现了类似于带有路由的事件。基本上,
EventRoute
MaterialPageRoute
的替代品,它为小部件创建、推到前台、推到后台以及弹出时提供可选回调

事件路径。飞镖

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);
  }
}

尽管背景有点令人讨厌……

所有的问题都解决了

从窗口小部件树(materialappwidget)的根将观察者放置在导航器上

如果您需要更多解释,请点击此链接:

我已经在我的项目中实现了它,它在@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();
}
//将RouteObserver注册为导航观察员。
最终RouteObserver RouteObserver=RouteObserver();
void main(){
runApp(材料应用程序)(
主页:Container(),
NavigatorObserver:[routeObserver],
));
}
类RouteAwareWidget扩展StatefulWidget{
State createState()=>RouteAwareWidgetState();
}
//在小部件的状态下实现RouteAware并订阅它
//
//RouteObserver。
类RouteAwareWidgetState使用RouteAware扩展状态{
@凌驾
void didChangeDependencies(){
super.didChangeDependencies();
subscribe(这是(上下文)的ModalRoute.of);
}
@凌驾
无效处置(){
routeObserver.unsubscribe(此);
super.dispose();
}
@凌驾
void didPush(){
//路线被推到了导航器上,现在是最上面的路线。
}
@凌驾
void didPopNext(){
//覆盖路线从导航器上弹出。
}
@凌驾
小部件构建(BuildContext上下文)=>Container();
}

当我没有看到我的应用程序的主屏幕时,我很难让视频暂停。我应用了这个
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();
  }
VisibilityDetector(
key:key('visible-video--key-${this.randomkeygenerator}-1'),
onVisibilityChanged:(visibilityInfo){
var visiblePercentage=visibilityInfo.visibleFraction*100;
如果(visiblePercentage<1){//,魔法就在这里完成了
如果(\u视频\u控制器!=null){
if(disposed_vid==false){
_视频控制器。暂停();
}
}
}否则{
如果(\u视频\u控制器!=null){
if(disposed_vid==false){
_视频控制器。播放();
}
}
}
调试打印(
'小部件${visibilityInfo.key}是${visiblePercentage}%visible');
},
子:视频播放器(_视频控制器)),
@凌驾
无效处置(){
//如果正在播放视频,请将其暂停。
_视频控制器。暂停();
_video_controller.dispose();
disposed_vid=真;
super.dispose();
}

因为背景路线的动画将被禁用。所以我们可以这样判断它是否在前景中:

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;
  }
}
///由ipcjs于2021/3/23创建。
类ForegroundDetector扩展StatefulWidget{
常数前地探测器({
钥匙?,钥匙,
需要这个孩子,
需要此项。onForegroundChanged,
}):super(key:key);
最终价值在前期发生变化;
最后一个孩子;
@凌驾
ForegroundDetectorState createState()=>ForegroundDetectorState();
}
类ForegroundDetectorState扩展了状态{
bool get isForeground=>\u isForeground??false;
布尔?\u是前景;
@凌驾
小部件构建(构建上下文){
最终isForeground=TickerMode.of(上下文);
如果(_isForeground!=isForeground){
_isForeground=isForeground;
onForegroundChanged(isForeground);
}
返回widget.child;
}
}

不重复。我提到我不是在问关于didChangeAppLifecycleState的问题。我的用例是不同的@tokenyet当你在另一个屏幕时,如果你弹回到视频屏幕,你可以在
Navigator.pop(context,parameter)
中传递一个参数,因此在视频屏幕中你将得到参数并相应地做一些事情。看这篇文章哦,我终于知道你不是在简历上写什么了。这更多的是关于页面转换,看起来你有解决办法。为了避免谈论太多的代码,我宁愿在
Navigator之前停止。按
等待Navigator.pop
继续视频。如果您没有使用
Navigator
,您可能需要提供更多的代码来向我们展示:请键入下面的答案,哪种方法等效于onPause(),哪种方法等效于onResume()?我假设didPush()类似于onResume(),didPop()类似于onPause()。我说得对吗?我的理解正确吗?我对didPopNext()和didPop()感到困惑。didPopNext()是否与onResume()相同?我无法在@software person和
等待导航器处获得您的答案。push(…)
作为@Token对我有效,但在评论中提到我创建了一个EventRoute类。它是一个类,用于在创建小部件、推送到前台、推送到后台以及弹出小部件时提供可选回调。所有这些活动都是可选的
/// 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;
  }
}