Flutter二维码扫描插件code_scanner的使用
Flutter二维码扫描插件code_scanner的使用
code_scanner
是一个用于Flutter的二维码扫描插件,支持通过摄像头扫描二维码以及从相册中选择图片读取二维码。该插件会响应相机和相册的权限请求,并提供扫描和读取功能。
平台支持
- iOS: 支持iOS 8.0及以上版本
- Android: 最低支持API 23
配置
iOS配置
在 info.plist
文件中添加以下内容:
<key>NSCameraUsageDescription</key>
<string>需要访问您的相机以进行二维码扫描</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问您的相册以读取二维码图片</string>
<key>io.flutter.embedded_views_preview</key>
<true/>
Android配置
在 AndroidManifest.xml
文件中添加以下内容:
<manifest ... xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
</manifest>
依赖库
- iOS: 使用 MTBBarcodeScanner
- Android: 使用 zxing-android-embedded
使用方法
View & View Controller
CodeScanner
是用于显示二维码扫描界面的Widget,CodeScannerController
是用于控制扫描行为的控制器。
/// 扫描Widget
CodeScanner(
controller: controller,
isScanFrame: true, // 是否显示扫描框,默认为true
scanFrameSize: Size(200, 200), // 扫描框大小,默认为200x200
frameWidth: 8, // 扫描框边框宽度,默认为8
frameColor: Color(0xcc222222), // 扫描框颜色,默认为深灰色
)
/// Widget控制器
controller = CodeScannerController();
获取扫描数据
通过监听 scanDataStream
流来获取扫描到的二维码数据。
/// 监听扫描数据
controller.scanDataStream.listen((data) {
print('扫描到的数据: $data');
});
获取读取数据
如果从相册中读取二维码图片成功,isSuccessReadDataStream
流会返回 true
;如果失败,则返回 false
。你也可以直接监听 readDataStream
流来获取读取结果,成功时返回实际数据,失败时返回 null
。
/// 监听读取成功的标志
controller.isSuccessReadDataStream.listen((success) {
if (success) {
print('读取成功');
} else {
print('读取失败');
}
});
/// 监听读取数据
controller.readDataStream.listen((data) {
if (data != null) {
print('读取到的数据: $data');
} else {
print('读取失败');
}
});
方法
- 开始扫描:
await controller.startScan();
(当CodeScanner
创建时会自动调用此方法) - 停止扫描:
await controller.stopScan();
(默认在控制器销毁时调用) - 从相册读取二维码:
await controller.readDataFromGallery();
- 打开闪光灯:
await controller.lightON();
- 关闭闪光灯:
await controller.lightOFF();
- 切换闪光灯:
await controller.toggleLight();
完整示例代码
以下是一个完整的示例代码,展示了如何使用 code_scanner
插件进行二维码扫描和从相册读取二维码。
import 'package:code_scanner/code_scanner.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: CodeScannerHome()));
}
class CodeScannerHome extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('QR Scanner Example'),
),
body: Center(
child: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => CodeScannerExample()),
);
},
child: Icon(Icons.camera_alt),
),
),
);
}
}
class CodeScannerExample extends StatefulWidget {
[@override](/user/override)
_CodeScannerExampleState createState() => _CodeScannerExampleState();
}
class _CodeScannerExampleState extends State<CodeScannerExample> {
CodeScannerController controller;
[@override](/user/override)
void initState() {
super.initState();
this.controller = CodeScannerController();
}
[@override](/user/override)
void dispose() {
controller.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('QR Scanner'),
leading: IconButton(
key: Key('closeButton'),
icon: const Icon(Icons.close),
onPressed: () {
Navigator.pop(context, '');
},
),
),
body: Stack(
alignment: AlignmentDirectional.center,
children: [
// 扫描区域
CodeScanner(
controller: controller,
isScanFrame: true,
frameColor: Color(0xcc222222),
),
// 提示文本
Container(
margin: const EdgeInsets.only(bottom: 500),
padding: const EdgeInsets.all(5.0),
width: 300,
decoration: BoxDecoration(
color: Color(0xcc222222),
border: Border.all(color: Color(0xcc222222)),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'Scan code',
style: TextStyle(color: Colors.white, fontSize: 17),
textAlign: TextAlign.center,
),
),
// 显示扫描结果
Container(
margin: const EdgeInsets.only(top: 350),
padding: const EdgeInsets.all(5.0),
width: 300,
decoration: BoxDecoration(
color: Color(0xcc222222),
border: Border.all(color: Color(0xcc222222)),
borderRadius: BorderRadius.circular(10),
),
child: StreamBuilder<String>(
stream: controller.scanDataStream,
builder: (context, snapshot) {
return Text(
'Scan Data: ${snapshot.data}',
style: TextStyle(color: Colors.white, fontSize: 17),
textAlign: TextAlign.center,
);
},
),
),
// 显示读取结果
Container(
margin: const EdgeInsets.only(top: 450),
padding: const EdgeInsets.all(5.0),
width: 300,
decoration: BoxDecoration(
color: Color(0xcc222222),
border: Border.all(color: Color(0xcc222222)),
borderRadius: BorderRadius.circular(10),
),
child: StreamBuilder<String>(
stream: controller.readDataStream,
builder: (context, snapshot) {
return (snapshot.hasData)
? Text(
'Read Data: ${snapshot.data}',
style: TextStyle(color: Colors.white, fontSize: 17),
textAlign: TextAlign.center,
)
: Text(
'Read Failure',
style: TextStyle(color: Colors.white, fontSize: 17),
textAlign: TextAlign.center,
);
}),
),
// 操作按钮
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
margin: const EdgeInsets.only(top: 600),
child: FloatingActionButton(
heroTag: "hero1",
child: Icon(Icons.lightbulb_outline),
backgroundColor: Color(0xcc222222),
onPressed: () async {
await controller.toggleLight();
},
),
),
Container(
margin: const EdgeInsets.only(top: 600),
child: FloatingActionButton(
heroTag: "hero2",
child: Icon(Icons.photo_library),
backgroundColor: Color(0xcc222222),
onPressed: () async {
await controller.readDataFromGallery();
},
),
),
],
),
],
),
);
}
}
更多关于Flutter二维码扫描插件code_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter二维码扫描插件code_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter应用中使用code_scanner
插件进行二维码扫描的示例代码。这个示例将展示如何集成该插件、请求必要的权限以及实现二维码扫描功能。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加code_scanner
依赖:
dependencies:
flutter:
sdk: flutter
code_scanner: ^4.0.0 # 请检查最新版本号并替换
然后运行flutter pub get
来安装依赖。
2. 请求权限
在Android和iOS上扫描二维码通常需要相机权限。因此,你需要在AndroidManifest.xml
和Info.plist
中声明这些权限。
Android (AndroidManifest.xml
)
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
iOS (Info.plist
)
<key>NSCameraUsageDescription</key>
<string>需要访问相机以扫描二维码</string>
3. 实现二维码扫描功能
接下来,在你的Flutter代码中实现二维码扫描功能。以下是一个完整的示例:
import 'package:flutter/material.dart';
import 'package:code_scanner/code_scanner.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ScannerPage(),
);
}
}
class ScannerPage extends StatefulWidget {
@override
_ScannerPageState createState() => _ScannerPageState();
}
class _ScannerPageState extends State<ScannerPage> {
final CodeScannerController _controller = CodeScannerController();
String? result;
bool isPermissionGranted = false;
@override
void initState() {
super.initState();
_controller.addListener(() {
setState(() {
result = _controller.value.text;
});
});
_requestPermission();
}
Future<void> _requestPermission() async {
var status = await Permission.camera.status;
if (!status.isGranted) {
var result = await Permission.camera.request();
if (result.isGranted) {
setState(() {
isPermissionGranted = true;
});
_controller.start();
}
} else {
setState(() {
isPermissionGranted = true;
});
_controller.start();
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('二维码扫描'),
),
body: Center(
child: isPermissionGranted
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 5,
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: CodeScannerViewBuilder(
builder: (BuildContext context, CodeScannerController? controller) =>
CustomOverlay(
controller: controller!,
result: result,
),
),
),
),
SizedBox(height: 20),
Expanded(
child: Text(
result ?? 'No result',
style: TextStyle(fontSize: 24),
textAlign: TextAlign.center,
),
),
],
)
: Center(
child: ElevatedButton(
onPressed: () async {
await _requestPermission();
},
child: Text('请求相机权限'),
),
),
),
);
}
}
class CustomOverlay extends StatelessWidget {
final CodeScannerController controller;
final String? result;
CustomOverlay({required this.controller, required this.result});
@override
Widget build(BuildContext context) {
var color = Colors.red.withOpacity(0.5);
return Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
left: 0,
right: 0,
top: 0,
bottom: 0,
child: Opacity(
opacity: controller.value.isScanning ? 0.5 : 0.0,
child: ColorFiltered(
colorFilter: ColorFilter.mode(color, BlendMode.darken),
child: FlutterLogo(size: 100),
),
),
),
if (controller.value.isScanning)
Positioned(
bottom: 10,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Scanning...',
style: TextStyle(color: Colors.white, fontSize: 20),
),
],
),
),
if (result != null)
Positioned(
bottom: 80,
left: 20,
right: 20,
child: Card(
elevation: 8,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Result: $result',
style: TextStyle(fontSize: 24, color: Colors.black),
),
),
),
),
],
);
}
}
解释
- 权限请求:使用
permission_handler
插件请求相机权限。 - 初始化
CodeScannerController
:在initState
方法中初始化控制器并监听扫描结果。 - UI布局:根据权限状态显示不同的UI。如果权限已授予,则显示二维码扫描视图和扫描结果;否则,显示请求权限的按钮。
- 自定义覆盖层:使用
CustomOverlay
小部件自定义扫描视图上的覆盖层,包括扫描提示和结果显示。
这个示例展示了如何在Flutter应用中集成并使用code_scanner
插件进行二维码扫描。请确保在实际项目中处理错误和异常情况,并根据需要进行UI调整。