flutter - 如何在 Flutter 中启用相机闪光灯?

标签 flutter

我正在尝试使用 Flutter 中的相机使用手电筒闪光灯拍照。如何添加拍照时使用手电筒闪光灯的选项?

我使用以下相机包:https://pub.dev/packages/camera#-installing-tab-对于相机。我已经尝试过 https://pub.dev/packages/lamphttps://pub.dev/packages/torch用于打开手电筒并使其闪烁的软件包。在我看来,相机包中没有内置手电筒功能,因此我尝试使用单独的手电筒包。

TakePictureScreen小部件:

class TakePictureScreenState extends State<TakePictureScreen> {
  CameraController _controller;
  Future<void> _initializeControllerFuture;
  double displayWidth = 1;
  double displayHeight = 1;
  bool showFlashButton;
  bool isFlashActivated;

  @override
  void initState() {
    super.initState();
    showFlashButton = false;
    isFlashActivated = false;
    switchShowLampButton();
    _controller = CameraController(widget.camera, ResolutionPreset.high);
    _initializeControllerFuture = _controller.initialize();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    displayWidth = MediaQuery.of(context).size.width;
    displayHeight = MediaQuery.of(context).size.height;
    return WillPopScope(
      child: Scaffold(
        appBar: AppBar(backgroundColor: Color(0xFF276272)),
        body: FutureBuilder<void>(
          future: _initializeControllerFuture,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              return CameraPreview(_controller);
            } else {
              // Otherwise, display a loading indicator
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
        floatingActionButton: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Flexible(
              child: buildCameraButton(),
            ),
            Flexible(
              child: buildFlashButton(),
            )
          ],
        ),
      ),
      onWillPop: onPop,
    );
  }

  Future<bool> onPop() async {
    Navigator.pop(this.context, null);
    return false;
  }

  Future cameraButtonPressed() async {
    try {
      await _initializeControllerFuture;

      // Construct the path where the image should be saved using the path
      // package.
      final path = join(
        // In this example, store the picture in the temp directory. Find
        // the temp directory using the `path_provider` plugin.
        (await getTemporaryDirectory()).path,
        '${DateTime.now()}.png',
      );

      // Attempt to take a picture and log where it's been saved
      await _controller.takePicture(path);

      // If the picture was taken, display it on a new screen
      Future<bool> savePhotoOnPop = Navigator.push(
        this.context,
        MaterialPageRoute(
          builder: (context) => DisplayPictureScreen(imagePath: path),
        ),
      );

      savePhotoOnPop.then((savePhoto) {
        if (savePhoto) {
          var file = File(path);
          var fileBytesFuture = file.readAsBytes();
          fileBytesFuture.then((fileBytes) {
            Navigator.pop(this.context, fileBytes);
          });
        }
      });
    } catch (e) {
      print(e);
    }
  }

  void flashButtonPressed() async {
    await Lamp.turnOn(intensity: 1.0);
    setState(() {
      isFlashActivated = !isFlashActivated;
    });
  }

  Widget buildCameraButton() {
    return Container(
      margin: EdgeInsets.only(bottom: displayHeight * 0.01),
      width: displayWidth * 0.175,
      height: displayWidth * 0.175,
      child: RawMaterialButton(
        shape: CircleBorder(),
        fillColor: Color(0xff10846D),
        onPressed: cameraButtonPressed,
        child: Icon(
          Icons.camera_alt,
          color: Colors.white,
          size: displayWidth * 0.1,
        ),
      ),
    );
  }

  Widget buildFlashButton() {
    if (showFlashButton)
      return Container(
        width: displayWidth * 0.175,
        height: displayWidth * 0.175,
        child: RawMaterialButton(
          shape: CircleBorder(),
          fillColor: Color(0xff10846D),
          onPressed: flashButtonPressed,
          child: Icon(
            isFlashActivated ? Icons.flash_on : Icons.flash_off,
            color: isFlashActivated ? Colors.white : Color(0xFF999999),
            size: displayWidth * 0.1,
          ),
        ),
      );
    else
      return SizedBox(height: 0);
  }

  void switchShowLampButton() {
    Lamp.hasLamp.then((hasLamp) {
      setState(() {
        showFlashButton = hasLamp;
      });
    });
  }
}

当调用 flashButtonPressed() 时,我希望手机上的手电筒会打开。

根据我是否使用 Lamp- 或 Torch 包,有两种不同的结果:

  • 灯包:没有异常或错误,但 torch 从未打开且没有任何反应。

  • Torch 软件包:我收到以下错误“由于现有相机用户,相机“0”的 Torch 不可用”。

所以,同时使用手电筒和相机似乎存在冲突。但由于我在相机包中没有看到任何内置选项可以在拍照时使用手电筒,所以我不知道如何解决这个问题。

谢谢!

最佳答案

lamp 仅支持 API 20 (Kitkat),使用 torch相反,依赖。

这是使用 torch 依赖项的示例

class CameraHomeScreen extends StatefulWidget {
  final List<CameraDescription> cameras;

  CameraHomeScreen(this.cameras);

  @override
  State<StatefulWidget> createState() {
    return _CameraHomeScreenState();
  }
}

class _CameraHomeScreenState extends State<CameraHomeScreen> {
  String imagePath;
  bool _toggleCamera = false;
  bool _toggleFlash = false;
  String _icFlash = "assets/icons/ic_flash_off.png";
  String _lensDirection = "CameraLensDirection.back";
  CameraController controller;

  @override
  void initState() {
    try {
      onCameraSelected(widget.cameras[0]);
    } catch (e) {
      print(e.toString());
    }
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    if (widget.cameras.isEmpty) {
      return Container(
        alignment: Alignment.center,
        padding: EdgeInsets.all(16.0),
        child: Text(
          'No Camera Found',
          style: TextStyle(
            fontSize: 16.0,
            color: Colors.white,
          ),
        ),
      );
    }

    if (!controller.value.isInitialized) {
      return Container();
    }

    return Transform.scale(
      scale: 1 / controller.value.aspectRatio,
      child: Center(
        child: AspectRatio(
          aspectRatio: controller.value.aspectRatio,
          child: Container(
            child: Stack(
              children: <Widget>[
                CameraPreview(controller),
                Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    width: MediaQuery.of(context).size.width,
                    height: 100.0,
                    color: Colors.transparent,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: <Widget>[
                        _lensDirection == "CameraLensDirection.back" ? Material(
                          color: Colors.transparent,
                          child: InkWell(
                            borderRadius:
                                BorderRadius.all(Radius.circular(50.0)),
                            onTap: () async {
                              bool hasTorch = await Torch.hasTorch;
                              if (hasTorch) {
                                if (!_toggleFlash) {
                                  Torch.turnOn();
                                  setState(() {
                                    _icFlash = "assets/icons/ic_flash_on.png";
                                    _toggleFlash = true;
                                  });
                                } else {
                                  Torch.turnOff();
                                  setState(() {
                                    _icFlash = "assets/icons/ic_flash_off.png";
                                    _toggleFlash = false;
                                  });
                                }
                              }
                            },
                            child: Container(
                              child: Image.asset(
                                _icFlash,
                                width: 15.0,
                                height: 15.0,
                              ),
                            ),
                          ),
                        ) : Container(
                          width: 15.0,
                          height: 15.0,
                        ),
                        Material(
                          color: Colors.transparent,
                          child: InkWell(
                            borderRadius:
                                BorderRadius.all(Radius.circular(50.0)),
                            onTap: () {
                              _captureImage();
                            },
                            child: Container(
                              child: Image.asset(
                                'assets/icons/ic_shutter.png',
                                width: 50.0,
                                height: 50.0,
                              ),
                            ),
                          ),
                        ),
                        Material(
                          color: Colors.transparent,
                          child: InkWell(
                            borderRadius:
                                BorderRadius.all(Radius.circular(50.0)),
                            onTap: () {
                              if (!_toggleCamera) {
                                onCameraSelected(widget.cameras[1]);
                                setState(() {
                                  _toggleCamera = true;
                                });
                              } else {
                                onCameraSelected(widget.cameras[0]);
                                setState(() {
                                  _toggleCamera = false;
                                });
                              }
                            },
                            child: Container(
                              child: Image.asset(
                                'assets/icons/ic_switch_camera.png',
                                width: 18.0,
                                height: 18.0,
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  void onCameraSelected(CameraDescription cameraDescription) async {
    if (controller != null) await controller.dispose();
    controller = CameraController(cameraDescription, ResolutionPreset.medium);
    controller.addListener(() {
      if (mounted) setState(() {
        _icFlash = "assets/icons/ic_flash_off.png";
        _toggleFlash = false;
        _lensDirection = cameraDescription.lensDirection.toString();
      });
      if (controller.value.hasError) {
        showMessage('Camera Error: ${controller.value.errorDescription}');
      }
    });

    try {
      await controller.initialize();
    } on CameraException catch (e) {
      showException(e);
    }

    if (mounted) setState(() {});
  }

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

  void _captureImage() {
    takePicture().then((String filePath) {
      if (mounted) {
        setState(() {
          imagePath = filePath;
        });
        if (filePath != null) {
          showMessage('Picture saved to $filePath');
          setCameraResult();
        }
      }
    });
  }

  void setCameraResult() {
//    Navigator.pop(context, imagePath);
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => Preview(path: imagePath)),
    );
  }

  Future<String> takePicture() async {
    if (!controller.value.isInitialized) {
      showMessage('Error: select a camera first.');
      return null;
    }
    final Directory extDir = await getApplicationDocumentsDirectory();
    final String dirPath = '${extDir.path}/FlutterDevs/Camera/Images';
    await new Directory(dirPath).create(recursive: true);
    final String filePath = '$dirPath/${timestamp()}.jpg';

    if (controller.value.isTakingPicture) {
      // A capture is already pending, do nothing.
      return null;
    }

    try {
      await controller.takePicture(filePath);
    } on CameraException catch (e) {
      showException(e);
      return null;
    }
    return filePath;
  }

  void showException(CameraException e) {
    logError(e.code, e.description);
    showMessage('Error: ${e.code}\n${e.description}');
  }

  void showMessage(String message) {
    print(message);
  }

  void logError(String code, String message) =>
      print('Error: $code\nMessage: $message');
}

关于flutter - 如何在 Flutter 中启用相机闪光灯?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57571306/

相关文章:

date - 从Cloud_Firestore到日期的Flutter Dart错误格式时间步

firebase - PluginRegistry无法转换为FlutterEngine

flutter - 我如何在 flutter 中听取 UIApplication 生命周期 iOS

Flutter:创建带有可选 body 部位的 BodyMap 小部件

flutter - 致命异常 : TokenRefresher

android - Google 登录 "Choose an account to continue"循环

flutter - 从真正的移动浏览器访问 flutter localhost

flutter - 无法在 map 中添加多个数据

Flutter:textAlign:TextAlign.end 在 TextField/TextFormField 中不起作用

flutter - elevatedButtonTheme 的 textStyle 属性不会更改 ElevatedButton 中的文本颜色