Skip to content

[Flutter] 如何使用照相機拍照、展示圖片

在 Flutter 專案中,若是想要調用手機照相機的鏡頭拍照、並展示拍出的相片並不是件難事。對我而言,比較困難的則是把相片儲存在手機的相簿中、甚至是寫一個裁切相片的功能;當然,目前我還在研究當中。

本篇文章則根據 Flutter 官方教學文件:Take a picture using the camera 來紀錄如何在 Flutter 專案中調用照相機鏡頭。


準備工作

Step 1: 添加相關依賴套件 (dependencies)

在調用照相機前,我們會需要將下列三個相關依賴添加於 pubspec.yaml 當中。

  • camera: 提供與設備照相機相關工具
  • path_provider: 查詢正確路徑儲存照片
  • path: 建立在任何平台上都可運作的路徑
dependencies:
  flutter:
    sdk: flutter
  camera:
  path_provider:
  path:




Step 2: 不同平台的設定

如果在 Android 平台上,需要確認 minSdkVersion 至少為 21。(相關設定請參考:[已解決][Flutter] Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared in library [:camera]

在 iOS 平台上,需要在 ios/Runner/Info.plist 中添加:

<key>NSCameraUsageDescription</key>
<string>Explanation on why the camera access is needed.</string>

範例程式碼

import 'dart:async';
import 'dart:io';

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


Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Obtain a list of available cameras
  final cameras = await availableCameras();

  // Get a specific camera (first one)
  final firstCamera = cameras.first;

  runApp(
    MaterialApp(
      home: TakePicturePage(
        camera: firstCamera,
      )
    )
  );
}


// Take picture page
class TakePicturePage extends StatefulWidget {
  final CameraDescription camera;

  const TakePicturePage({
    Key key,
    @required this.camera,
  }) : super(key: key);

  @override
  TakePicturePageState createState() => TakePicturePageState();
}


// Take picture page state
class TakePicturePageState extends State<TakePicturePage> {
  CameraController _controller;
  Future<void> _initializeControllerFuture;

  @override
  void initState() {
    // Init
    super.initState();
    _controller = CameraController(
      // Camera settings
      widget.camera,
      ResolutionPreset.max,
    );

    // Initialize the controller
    _initializeControllerFuture = _controller.initialize();
  }

  // Dispose of the controller when the widget is disposed
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Take a picture demo")
      ),
      body: FutureBuilder<void>(
        future: _initializeControllerFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            return CameraPreview(_controller);
          }
          else {
            return Center(child: CircularProgressIndicator());
          }
        },
      ),

      floatingActionButton: Container(
        height: 75.0,
        width: 75.0,
        child: FittedBox(
          child: FloatingActionButton(
              backgroundColor: Colors.white,
              child: Icon(
                Icons.camera_alt_rounded,
                color: Colors.black,
              ),
              onPressed: () async {
                try {
                  await _initializeControllerFuture;
                  final image = await _controller.takePicture();

                  // If the picture was taken
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => DisplayPicturePage(
                        imagePath: image?.path,
                      ),
                    ),
                  );

                  print("My Image Path:");
                  print(image?.path);
                }
                catch (error) {
                  print(error);
                }
              }
          ),
        ),
      ),

      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}


// A new page for displaying the picture
class DisplayPicturePage extends StatelessWidget {
  final String imagePath;
  const DisplayPicturePage({Key key, this.imagePath}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Display the picture")
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            Text("$imagePath"),
            Container(
              width: MediaQuery.of(context).size.width/2,
              height: MediaQuery.of(context).size.height/2,
              child: Image.file(File(imagePath)),
            ),
          ],
        )
      )
    );
  }
}



Output:

拍照頁面
展示頁面

可以展示圖片上方的路徑看出,這種方法拍攝的相片並不是儲存在手機的相片庫之類的地方,而是放置於快取cache)當中。


References


Read More

Tags:

Leave a Reply