草庐IT

widget - Flutter:小部件和导航的生命周期

coder 2023-05-09 原文

我编写了一个 flutter 插件,它可以显示相机预览并扫描条形码。我有一个名为 ScanPageWidget,它显示 CameraPreview 并在检测到条形码时导航到新的 Route

问题: 当我将新路线 (SearchProductPage) 推送到导航堆栈时,CameraController 会继续检测条形码。当 ScanPage 从屏幕上移除时,我需要在 CameraController 上调用 stop()。当用户返回 ScanPage 时,我需要再次调用 start()

我尝试了什么: CameraController 实现 WidgetsBindingObserver 并对 didChangeAppLifecycleState() 作出 react 。当我按下主页按钮时,这非常有效,但当我将新的 Route 推送到导航堆栈时却不行。

问题: iOS 上的 viewDidAppear()viewWillDisappear()onPause()onResume() 是否有等价物在 Android 上用于 Flutter 中的 Widgets?如果没有,我如何启动和停止我的 CameraController 以便当另一个小部件位于导航堆栈顶部时它停止扫描条形码?

class ScanPage extends StatefulWidget {

  ScanPage({ Key key} ) : super(key: key);

  @override
  _ScanPageState createState() => new _ScanPageState();

}

class _ScanPageState extends State<ScanPage> {

  //implements WidgetsBindingObserver
  CameraController controller;

  @override
  void initState() {

    controller = new CameraController(this.didDetectBarcode);
    WidgetsBinding.instance.addObserver(controller);

    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      setState(() {});
    });
  }

  //navigate to new page
  void didDetectBarcode(String barcode) {
      Navigator.of(context).push(
          new MaterialPageRoute(
            builder: (BuildContext buildContext) {
              return new SearchProductPage(barcode);
            },
          )
      );    
  }

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

  @override
  Widget build(BuildContext context) {

    if (!controller.value.initialized) {
      return new Center(
        child: new Text("Lade Barcodescanner..."),
      );
    }

    return new CameraPreview(controller);
  }
}

编辑:

/// Controls a device camera.
///
///
/// Before using a [CameraController] a call to [initialize] must complete.
///
/// To show the camera preview on the screen use a [CameraPreview] widget.
class CameraController extends ValueNotifier<CameraValue> with WidgetsBindingObserver {

  int _textureId;
  bool _disposed = false;

  Completer<Null> _creatingCompleter;
  BarcodeHandler handler;

  CameraController(this.handler) : super(const CameraValue.uninitialized());

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {

    switch(state){
      case AppLifecycleState.inactive:
        print("--inactive--");
        break;
      case AppLifecycleState.paused:
        print("--paused--");
        stop();
        break;
      case AppLifecycleState.resumed:
        print("--resumed--");
        start();
        break;
      case AppLifecycleState.suspending:
        print("--suspending--");
        dispose();
        break;
    }
  }

  /// Initializes the camera on the device.
  Future<Null> initialize() async {

    if (_disposed) {
      return;
    }
    try {
      _creatingCompleter = new Completer<Null>();
      _textureId = await BarcodeScanner.initCamera();

      print("TextureId: $_textureId");

      value = value.copyWith(
        initialized: true,
      );
      _applyStartStop();
    } on PlatformException catch (e) {
      value = value.copyWith(errorDescription: e.message);
      throw new CameraException(e.code, e.message);
    }

    BarcodeScanner._channel.setMethodCallHandler((MethodCall call){
      if(call.method == "barcodeDetected"){
        String barcode = call.arguments;
        debounce(2500, this.handler, [barcode]);
      }
    });

    _creatingCompleter.complete(null);
  }

  void _applyStartStop() {
    if (value.initialized && !_disposed) {
      if (value.isStarted) {
        BarcodeScanner.startCamera();
      } else {
        BarcodeScanner.stopCamera();
      }
    }
  }

  /// Starts the preview.
  ///
  /// If called before [initialize] it will take effect just after
  /// initialization is done.
  void start() {
    value = value.copyWith(isStarted: true);
    _applyStartStop();
  }

  /// Stops the preview.
  ///
  /// If called before [initialize] it will take effect just after
  /// initialization is done.
  void stop() {
    value = value.copyWith(isStarted: false);
    _applyStartStop();
  }

  /// Releases the resources of this camera.
  @override
  Future<Null> dispose() {
    if (_disposed) {
      return new Future<Null>.value(null);
    }
    _disposed = true;
    super.dispose();
    if (_creatingCompleter == null) {
      return new Future<Null>.value(null);
    } else {
      return _creatingCompleter.future.then((_) async {
        BarcodeScanner._channel.setMethodCallHandler(null);
        await BarcodeScanner.disposeCamera();
      });
    }
  }
}

最佳答案

在调用 pop() 时,在导航到另一个页面并重新启动它之前,我最终停止了 controller

//navigate to new page
void didDetectBarcode(String barcode) {
   controller.stop();
   Navigator.of(context)
       .push(...)
       .then(() => controller.start()); //future completes when pop() returns to this page

}

另一种解决方案是将打开 ScanPageroutemaintainState 属性设置为 false

关于widget - Flutter:小部件和导航的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50155206/

有关widget - Flutter:小部件和导航的生命周期的更多相关文章

  1. ruby-on-rails - 在 Rails 3 中向 Active Admin 添加全局导航项的最佳方法是什么 - 2

    我正在尝试将全局导航菜单项添加到我的ActiveAdmin安装(在“仪表板”导航按钮旁边)。ActiveAdmin说这在他们的网站上是可能的,但他们没有任何关于如何实现它的文档。有谁知道如何做到这一点?编辑:抱歉,我应该更清楚。我想添加一个指向由任意文本/链接对组成的全局导航的链接。IE,如果我想添加一个链接到http://google.com在事件管理员的全局导航中使用文本“Google”,我将如何实现? 最佳答案 ActiveAdmin.register_page"Google"domenu:priority=>1,:label

  2. 千耘农机导航的“星地一体”能力究竟是什么? - 2

    伴随农业机械化和智能化的发展,越来越多的人开始使用农机自动驾驶系统助力耕作,千耘农机导航的“星地一体”能力可有效解决信号受限的问题,实现作业提效。究竟什么是“星地一体”,又是如何解决智能化农机作业的痛点的?下面为大家揭秘。农机效率通常受限于通信网络目前虽然我国通讯网络的人口覆盖率达到99%,但地面移动通讯网络覆盖率仍小于国土面积的40%,而很多农田所在区域恰是山区、戈壁滩等偏远地区。两省交界地也会出现通信信号不稳定的状况;而国内大部分农机自动驾驶系统非常依赖通信网络,当通信网络弱的时候会出现系统掉线的现象,必须得携带小基站才能正常使用,极为繁琐。Q:什么是千耘农机导航“星地一体”能力?A:是星

  3. Flutter 环境变量配置和flutter doctor中的错误解决 - 2

    一、环境变量右键点击我的电脑-属性:然后找到环境变量 1.Android的SDK不在C盘的话需要额外配这个到用户环境变量:ANDROID_HOMED:\AndroidSDK2.然后在系统变量:Path中添加一条这样的值        D:\Flutter\flutter\bin             这个值写flutter包解压的实际地址即可 3.在系统变量中添加两个镜像变量:        变量名:FLUTTER_STORAGE_BASE_URL      变量值:https://storage.flutter-io.cn        变量名:PUB_HOSTED_URL      变量

  4. ruby - 在 Ruby 中查找周期和范围集差异的有效方法 - 2

    我在Ruby中有很多时间范围:period=Time.parse('8:00am')..Time.parse('8:00pm')incidents=[Time.parse('7:00am')..Time.parse('9:00am'),Time.parse('1:00pm')..Time.parse('3:00pm'),Time.parse('1:30pm')..Time.parse('3:30pm'),Time.parse('7:00pm')..Time.parse('9:00pm'),]我正试图在这段时间内获得一系列无事件block。对于以上内容:[Time.parse('9:00

  5. ruby-on-rails - 如何在不创建空模型的情况下创建 rails_admin 导航标签? - 2

    在railsadmin中,您可以像这样为模型及其子项定义导航标签:#inrails_admin.rbconfig.modelOrderdonavigation_label'Ordersrelated'endconfig.modelOrderProductsdoparentOrderend有没有办法在不创建模型的情况下向导航菜单添加标签(即仅用于分组)? 最佳答案 根据wiki,您可以像这样将静态链接附加到导航:RailsAdmin.configdo|config|config.navigation_static_links={'Go

  6. ruby-on-rails - 有没有一种简单的方法可以在 Passenger 的请求周期之外运行垃圾收集? - 2

    unicorn有OobGC可用于在一定数量的请求后运行GC.start的机架中间件。PhusionPassenger中有类似的东西吗? 最佳答案 PhusionPassenger4正式引入了带外垃圾回收机制。它比Unicorn更灵活,允许任意工作,而不仅仅是垃圾收集。http://blog.phusion.nl/2013/01/22/phusion-passenger-4-technology-preview-out-of-band-work/ 关于ruby-on-rails-有没有一种

  7. ruby - 为什么 Ruby 使用自己的安全导航运算符语法? - 2

    Ruby2.3.0引入了安全导航语法,它通过引入一个新的运算符来简化链式方法调用的nil处理,该运算符仅在先前语句的值不是nil。这是一个已经存在于C#、Groovy和Swift中的特性。例如inGroovy,语法是foo?.bar这基本上意味着结果值是foo.bar除非foo是null,在这种情况下返回值也是null因此不会抛出异常。还有C#(称为空条件运算符)和Swift(称为可选链接表达式)使用此表示法。所以语法在其他语言中似乎是相当标准的。现在,为什么在Ruby中语法是foo&.bar代替? 最佳答案 此答案基于thedis

  8. ruby - 如何在 Middleman 中生成导航? - 2

    我只是习惯了Middleman和一般的ruby。生成具有事件状态的导航的最佳方式是什么? 最佳答案 在当前版本的MM(2.x,尽管3.0接近)中,您可以通过向config.rb添加以下内容并在您的导航文件中进行一些调整来实现。这是aworkingversion以防我遗漏一些关键位:首先创建一个辅助函数:helpersdodefnav_active(page)@page_id==page?{:class=>"Active"}:{}endend然后,在navbarincludefile(在本例中它是一个haml文件)您可以使用nav_a

  9. ruby - 是否可以从功能文件导航到 VSCode 中的步骤定义 - 2

    我主要将RubyMine用于Cucumber/Ruby,现在,我开始使用VSCode,使用它可以运行和调试测试用例。我找不到从功能导航到步骤定义的方法。我尝试搜索扩展程序,但cucumber-step-mapper没有帮助。是否有任何配置可以实现从功能到步骤定义的导航? 最佳答案 您可以安装Cucumber(Gherkin)FullSupport来自VSCodeMarketplace的扩展:安装完成后,重新加载VSCode。现在为了使其适用于Ruby,您需要:按Ctrl+,打开用户设置向下滚动到CucumberAutoComplet

  10. ruby-on-rails - 如何在 Ruby on Rails 中实现特定于部分的导航? - 2

    我有一个Ruby/Rails应用程序,它有两个或三个主要“部分”。当用户访问该部分时,我希望显示一些子导航。所有三个部分都使用相同的布局,因此我无法将导航“硬编码”到布局中。我可以想到几种不同的方法来做到这一点。我想为了帮助人们投票,我会把它们作为答案。还有其他想法吗?或者你投票给什么? 最佳答案 假设每个部分都有自己的Controller,您可以使用partials轻松地做到这一点。假设您有三个部分,分别称为Posts、Users和Admin,每个部分都有自己的Controller:PostsController、UsersCon

随机推荐