Flutter切换扫描标签页时mobile_scanner相机不显示问题求助
Flutter切换标签页时相机无法显示的问题解决
问题现象
- 项目基于
mobile_scanner包实现两个扫码场景:Scan1使用barcode_scanner_window.dart,Scan2使用barcode_scanner_simple.dart,通过底部导航栏切换页面 - 从Home页切换到任意扫码页时,相机可正常显示
- 从一个扫码页直接切换到另一个扫码页时,目标页面相机无法显示(如Scan1→Scan2时Scan2黑屏,Home→Scan2→Scan1时Scan1黑屏)
项目代码
main.dart
import 'package:flutter/material.dart'; import 'package:mobile_scanner_bug/business.dart'; import 'package:mobile_scanner_bug/home.dart'; import 'package:mobile_scanner_bug/school.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Tab Bar Example', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _selectedIndex = 0; static const List<Widget> _widgetOptions = <Widget>[ Home(), School(), Business(), ]; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter Tab Bar'), ), body: Center( child: _widgetOptions.elementAt(_selectedIndex), ), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.camera), label: 'Scan1', ), BottomNavigationBarItem( icon: Icon(Icons.camera_alt), label: 'Scan2', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.amber[800], onTap: _onItemTapped, ), ); } }
school.dart(对应Scan1)
import 'package:flutter/material.dart'; import 'package:mobile_scanner_bug/barcode_scanner_window.dart'; class School extends StatefulWidget { const School({super.key}); @override State<School> createState() => _SchoolState(); } class _SchoolState extends State<School> { @override Widget build(BuildContext context) { return Stack( children: [ BarcodeScannerWithScanWindow(), Center(child: Text('Scan1')), ], ); } }
business.dart(对应Scan2)
import 'package:flutter/material.dart'; import 'package:mobile_scanner_bug/barcode_scanner_simple.dart'; class Business extends StatefulWidget { const Business({super.key}); @override State<Business> createState() => _BusinessState(); } class _BusinessState extends State<Business> { @override Widget build(BuildContext context) { return Stack( children: [ BarcodeScannerSimple(), const Center(child: Text('Scan2')), ], ); } }
home.dart
import 'package:flutter/material.dart'; class Home extends StatefulWidget { const Home({super.key}); @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { @override Widget build(BuildContext context) { return Center(child: Text('Home')); } }
问题原因及解决方法
原因
Flutter底部导航栏默认会缓存所有页面状态,两个扫码页同时存在于Widget树中时,mobile_scanner的相机资源会被先加载的页面占用,导致后切换的页面无法获取相机权限/资源,出现黑屏。
解决方法
方法1:控制相机生命周期(推荐,保留页面状态)
通过GlobalKey获取扫码页状态,切换标签时手动启停相机:
- 修改
main.dart中的_MyHomePageState:
class _MyHomePageState extends State<MyHomePage> { int _selectedIndex = 0; final GlobalKey<_SchoolState> _schoolKey = GlobalKey(); final GlobalKey<_BusinessState> _businessKey = GlobalKey(); void _onItemTapped(int index) { setState(() { // 切换前停止当前扫码页的相机 if (_selectedIndex == 1) { _schoolKey.currentState?.stopCamera(); } else if (_selectedIndex == 2) { _businessKey.currentState?.stopCamera(); } _selectedIndex = index; // 切换后启动目标扫码页的相机 if (_selectedIndex == 1) { _schoolKey.currentState?.startCamera(); } else if (_selectedIndex == 2) { _businessKey.currentState?.startCamera(); } }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter Tab Bar'), ), body: IndexedStack( index: _selectedIndex, children: [ const Home(), School(key: _schoolKey), Business(key: _businessKey), ], ), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.camera), label: 'Scan1', ), BottomNavigationBarItem( icon: Icon(Icons.camera_alt), label: 'Scan2', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.amber[800], onTap: _onItemTapped, ), ); } }
- 修改
school.dart添加相机控制方法:
import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; class School extends StatefulWidget { const School({super.key}); @override State<School> createState() => _SchoolState(); } class _SchoolState extends State<School> { late MobileScannerController _controller; @override void initState() { super.initState(); _controller = MobileScannerController(); } void startCamera() { _controller.start(); } void stopCamera() { _controller.stop(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Stack( children: [ MobileScanner(controller: _controller), Center(child: Text('Scan1')), ], ); } }
- 同理修改
business.dart:
import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; class Business extends StatefulWidget { const Business({super.key}); @override State<Business> createState() => _BusinessState(); } class _BusinessState extends State<Business> { late MobileScannerController _controller; @override void initState() { super.initState(); _controller = MobileScannerController(); } void startCamera() { _controller.start(); } void stopCamera() { _controller.stop(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Stack( children: [ MobileScanner(controller: _controller), const Center(child: Text('Scan2')), ], ); } }
方法2:动态重建页面(简单但无状态缓存)
修改main.dart,每次切换时动态构建页面,避免多个扫码页同时存在:
class _MyHomePageState extends State<MyHomePage> { int _selectedIndex = 0; Widget _getCurrentPage() { switch(_selectedIndex) { case 0: return const Home(); case 1: return const School(); case 2: return const Business(); default: return const Home(); } } void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter Tab Bar'), ), body: Center( child: _getCurrentPage(), ), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.camera), label: 'Scan1', ), BottomNavigationBarItem( icon: Icon(Icons.camera_alt), label: 'Scan2', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.amber[800], onTap: _onItemTapped, ), ); } }
内容的提问来源于stack exchange,提问作者Muhammad Taimoor
相关产品推荐
相关产品推荐

