Flutter相机使用插件easy_use_camera的功能

发布于 1周前 作者 itying888 来自 Flutter

Flutter相机使用插件easy_use_camera的功能

🌍 关于项目

本包用于在所有平台上使用相机拍摄照片和视频。

🛠 构建工具

源代码结构

/my_camera
  example/
        lib/
          main.dart
  lib/
    camera/
        dialog/
        widget/
        take_picture.dart
    my_camera.dart    

🧾 设置项目

Android
android {
  ...
  defaultConfig {
  minSdkVersion 21
  }
}
iOS
<key>NSCameraUsageDescription</key>
<string>本应用需要访问相机</string>
<key>NSMicrophoneUsageDescription</key>
<string>本应用需要访问麦克风</string>
PWA

需要在主机上启用SSL。

命名规范

什么 如何 示例
类、枚举、类型别名 大驼峰式命名 ProductBloc
库、包、目录、源文件名 下划线命名 product_detail_view
变量、常量、参数、命名参数 小驼峰式命名 variants

清洁代码

  • 创建UIKit组件库用于常见组件
  • 不直接使用颜色或字体样式,使用UIKit
  • 将组件拆分为子组件
  • 为每个功能创建组件包
  • 明确指定类成员类型
  • 使用if条件语句而不是条件表达式
  • 使用??和?.操作符
  • 使用级联操作符
    // 不推荐
    var path = Path();
    path.lineTo(0, size.height);
    path.lineTo(size.width, size.height);
    path.lineTo(size.width, 0);
    path.close();
    
    // 推荐
    var path = Path()
      ..lineTo(0, size.height)
      ..lineTo(size.width, size.height)
      ..lineTo(size.width, 0)
      ..close();
    
  • 在Widgets中使用Const

⛑ 代码审查

代码审查者关注的点

  • 设计:代码是否设计良好且适合您的系统?
  • 功能性:代码的行为是否符合作者的意图?代码的行为是否对用户友好?
  • 复杂度:代码是否可以简化?其他开发人员在未来阅读和使用此代码时是否容易理解?
  • 测试:代码是否有正确的自动化测试?
  • 命名:开发人员是否选择了清晰的变量、类、方法等名称?
  • 注释:注释是否清晰有用?
  • 风格:代码是否遵循我们的编码风格指南?
  • 文档:开发人员是否更新了相关的文档?

如何实施代码审查

  • 每个合并请求(Pull Request)必须满足以下检查列表,以确保过程中没有出现任何问题。
    • 检查分支是否未损坏
    • 检查功能是否实现
    • 检查测试用例是否通过
    • 检查代码风格(使用lint或手动)
    • 检查可读性
    • 检查副作用
    • 检查与其他类/包/模块的一致性
    • 检查合并请求上的所有注释
    • 审查者如果对合并请求有任何意见,可以在相应的行上留下评论。

📚 致谢


示例代码

example/lib/main.dart

import 'dart:io';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:easy_use_camera/easy_use_camera.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // 这个小部件是你的应用的根。
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(title),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: () async {
              final result = await takeFaceVideoOnDialog(
                context,
                direction: CameraLensDirection.front,
                resolutionPreset: ResolutionPreset.low,
                scanWidget: Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    width: double.maxFinite,
                    height: 100,
                    decoration: BoxDecoration(
                      color: Colors.amber.withOpacity(0.3)
                    ),
                  ),
                ),
              );
              if (context.mounted && result != null) {
                await Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (context) => PreviewVideo(
                      rotateAngle: math.pi / 2,
                      file: result,
                      topFaceBuilder: (context) {
                        return Center(
                          child: Text("Hello"),
                        );
                      },
                    ),
                  ),
                );
              }
            },
            child: Text('录制视频', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.black)),
          ),
          ElevatedButton(
            onPressed: () async {
              final result = await takeFacePictureOnDialog(context);
              if (result != null) {
                File file = File(result.path);
                print(file.path);
              }
            },
            child: const Text('拍摄人脸照片'),
          ),
          ElevatedButton(
            onPressed: () async {
              final result = await takeCardPictureOnDialog(context);
              if (result != null) {
                File file = File(result.path);
                print(file.path);
              }
            },
            child: const Text('拍摄卡片照片'),
          ),
          ElevatedButton(
            onPressed: () async {
              final result = await takeDocumentPictureOnDialog(context);
              if (result != null) {
                File file = File(result.path);
                print(file.path);
              }
            },
            child: const Text('拍摄文档照片'),
          ),
        ],
      ),
    );
  }
}

更多关于Flutter相机使用插件easy_use_camera的功能的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter相机使用插件easy_use_camera的功能的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个使用 easy_use_camera 插件在 Flutter 中实现相机功能的示例代码。easy_use_camera 插件简化了相机操作,使得集成相机功能变得更加容易。

首先,确保在你的 pubspec.yaml 文件中添加 easy_use_camera 依赖:

dependencies:
  flutter:
    sdk: flutter
  easy_use_camera: ^最新版本号  # 请替换为实际的最新版本号

然后运行 flutter pub get 来获取依赖。

接下来,在你的 Dart 文件中实现相机功能。以下是一个完整的示例,展示如何使用 easy_use_camera 插件:

import 'package:flutter/material.dart';
import 'package:easy_use_camera/easy_use_camera.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CameraScreen(),
    );
  }
}

class CameraScreen extends StatefulWidget {
  @override
  _CameraScreenState createState() => _CameraScreenState();
}

class _CameraScreenState extends State<CameraScreen> {
  late EasyUseCameraController _cameraController;

  @override
  void initState() {
    super.initState();
    // 初始化相机控制器
    _initCameraController();
  }

  @override
  void dispose() {
    // 释放相机控制器资源
    _cameraController.dispose();
    super.dispose();
  }

  Future<void> _initCameraController() async {
    _cameraController = EasyUseCameraController(
      // 可以传递一些配置参数,比如是否开启前置摄像头等
      ..initialize().then((_) {
        if (!mounted) return;
        setState(() {});
      }).catchError((Object err, StackTrace stack) {
        print('Failed to initialize camera: ${err.toString()}');
      }),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Camera Demo'),
      ),
      body: _cameraController.value.isInitialized
          ? Center(
              child: CameraPreview(_cameraController),
            )
          : Center(
              child: CircularProgressIndicator(),
            ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          // 拍照
          final XFile? image = await _cameraController.takePicture();
          if (image != null) {
            // 显示或处理图片
            print('Image saved to ${image.path}');
            // 可以在这里导航到另一个页面显示图片
            // Navigator.push(
            //   context,
            //   MaterialPageRoute(builder: (context) => ImagePreviewPage(image: image)),
            // );
          }
        },
        tooltip: 'Capture',
        child: Icon(Icons.camera_alt),
      ),
    );
  }
}

// 如果需要显示图片预览页面,可以添加以下代码
// class ImagePreviewPage extends StatelessWidget {
//   final XFile image;

//   ImagePreviewPage({required this.image});

//   @override
//   Widget build(BuildContext context) {
//     return Scaffold(
//       appBar: AppBar(
//         title: Text('Image Preview'),
//       ),
//       body: Center(
//         child: Image.file(File(image.path)),
//       ),
//     );
//   }
// }

在这个示例中:

  1. EasyUseCameraController 用于控制相机。
  2. initState 方法中初始化相机控制器。
  3. 使用 CameraPreview 小部件显示相机预览。
  4. 使用浮动操作按钮 (FAB) 拍照,并将拍摄的图片路径打印到控制台。

你可以根据需要扩展这个示例,比如添加图片预览页面或处理拍摄的图片。注意在实际项目中,要处理各种可能的错误和异常情况,以确保应用的健壮性。

回到顶部