Flutter实现相机拍照:使用camera插件

美食旅行家 2021-04-15 ⋅ 38 阅读

在移动应用开发中,相机功能是非常常见和实用的。Flutter作为流行的跨平台开发框架,为我们提供了使用相机的便捷方式。本文将使用Flutter的camera插件来实现相机拍照功能,并通过代码示例来说明具体的实现步骤。

安装camera插件

在开始之前,我们需要将camera插件添加到Flutter项目中。打开pubspec.yaml文件,在dependencies下添加camera插件的依赖项:

dependencies:
  flutter:
    sdk: flutter
  ...其他依赖
  camera: ^0.10.0+2

在终端中运行flutter packages get命令,以下载并安装插件。

初始化相机

在代码中引入camera插件:

import 'package:camera/camera.dart';

List<CameraDescription> cameras;

然后在void main()函数中,初始化相机:

Future<void> main() async {
  // 初始化相机
  WidgetsFlutterBinding.ensureInitialized();
  cameras = await availableCameras();
  runApp(MyApp());
}

显示相机预览

为了显示相机预览,我们将使用Flutter的CameraPreview小部件。在Flutter中,可以通过CameraController来控制和操作相机。我们需要将CameraControllerCameraPreview部件放置在Flutter的Scaffold部件中,并设置合适的大小和位置。

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

class _CameraScreenState extends State<CameraScreen> {
  CameraController controller;

  @override
  void initState() {
    super.initState();
    // 初始化相机预览
    controller = CameraController(cameras[0], ResolutionPreset.medium);
    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      setState(() {});
    });
  }

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

  @override
  Widget build(BuildContext context) {
    if (!controller.value.isInitialized) {
      return Container();
    }
    return Scaffold(
      body: Container(
        child: AspectRatio(
          aspectRatio: controller.value.aspectRatio,
          child: CameraPreview(controller),
        ),
      ),
    );
  }
}

在上述示例中,我们在initState()方法中初始化相机,并在build()方法中使用CameraPreview来显示预览。在dispose()方法中,我们需要记得释放相机资源。

拍照并保存照片

要实现拍照功能,我们需要添加一个按钮和一些逻辑来控制拍照的行为。在我们的代码示例中,我们将在相机预览上方添加一个按钮,并在按钮点击时触发拍照行为。

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

class _CameraScreenState extends State<CameraScreen> {
  CameraController controller;
  String imagePath;

  @override
  void initState() {
    super.initState();
    // 初始化相机预览
    controller = CameraController(cameras[0], ResolutionPreset.medium);
    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      setState(() {});
    });
  }

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

  Future<void> takePicture() async {
    if (!controller.value.isInitialized) {
      return;
    }
    final Directory extDir = await getTemporaryDirectory();
    final String dirPath = '${extDir.path}/Pictures/flutter_test';
    await Directory(dirPath).create(recursive: true);
    final String filePath = '$dirPath/${timestamp()}.jpg';

    if (controller.value.isTakingPicture) {
      return;
    }

    try {
      await controller.takePicture(filePath);
      setState(() {
        imagePath = filePath;
      });
    } catch (e) {
      print(e);
    }
  }

  String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();

  @override
  Widget build(BuildContext context) {
    if (!controller.value.isInitialized) {
      return Container();
    }
    return Scaffold(
      body: Container(
        child: AspectRatio(
          aspectRatio: controller.value.aspectRatio,
          child: Stack(
            children: <Widget>[
              CameraPreview(controller),
              Positioned(
                bottom: 48.0,
                left: 0,
                right: 0,
                child: Center(
                  child: IconButton(
                    icon: Icon(Icons.camera),
                    color: Colors.white,
                    onPressed: takePicture,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在上述示例中,takePicture()方法用于触发拍照操作。拍照后,我们将照片保存到设备上,并将照片路径存储在imagePath变量中。然后,我们在相机预览上方的按钮处使用Positioned小部件来放置拍照按钮。

显示拍摄的照片

要在拍照后显示照片,我们可以使用Flutter的Image.file()小部件。通过将照片路径传递给Image.file(),我们就可以把照片加载到界面上了。

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

class _CameraScreenState extends State<CameraScreen> {
  CameraController controller;
  String imagePath;

  @override
  void initState() {
    super.initState();
    // 初始化相机预览
    controller = CameraController(cameras[0], ResolutionPreset.medium);
    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      setState(() {});
    });
  }

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

  Future<void> takePicture() async {
    if (!controller.value.isInitialized) {
      return;
    }
    final Directory extDir = await getTemporaryDirectory();
    final String dirPath = '${extDir.path}/Pictures/flutter_test';
    await Directory(dirPath).create(recursive: true);
    final String filePath = '$dirPath/${timestamp()}.jpg';

    if (controller.value.isTakingPicture) {
      return;
    }

    try {
      await controller.takePicture(filePath);
      setState(() {
        imagePath = filePath;
      });
    } catch (e) {
      print(e);
    }
  }

  String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();

  @override
  Widget build(BuildContext context) {
    if (!controller.value.isInitialized) {
      return Container();
    }
    return Scaffold(
      body: Container(
        child: AspectRatio(
          aspectRatio: controller.value.aspectRatio,
          child: Stack(
            children: <Widget>[
              imagePath != null
                  ? Image.file(File(imagePath))
                  : CameraPreview(controller),
              Positioned(
                bottom: 48.0,
                left: 0,
                right: 0,
                child: Center(
                  child: IconButton(
                    icon: Icon(Icons.camera),
                    color: Colors.white,
                    onPressed: takePicture,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在上述示例中,我们在build()方法中使用了条件语句来判断是否有拍摄的照片。如果有,我们将加载照片;否则,我们将显示相机预览。

总结

通过上述代码示例,我们实现了Flutter中相机拍照功能的基本逻辑。我们使用了camera插件来初始化相机和显示预览,以及拍摄照片和显示照片。通过这个基础示例,你可以进一步扩展和改进相机拍照功能,以满足具体的项目需求。

希望本文对你了解如何使用Flutter实现相机拍照有所帮助。如果你有任何疑问或建议,请随时留言。谢谢阅读!


全部评论: 0

    我有话说: