搭建一個攝像頭應用程式 應用程式內部攝像頭

會煮咖啡的貓發表於2021-07-06

程式碼

github.com/jagrut-18/f…

參考

正文

在許多應用程式中,我們需要使用者通過點選圖片上傳圖片。為此,我們可以使用裝置的預設攝像頭應用程式,但如果我們需要整合一個應用程式內的攝像頭呢?那麼,這也是可能的 Flutter 。小組已經開發了一個叫做攝像頭的 pub.dev/packages/ca… ,它可以讓我們做到這一點。

建立專案

首先,通過在 pubspec.yaml 檔案中新增以下行,將 camera 包安裝到專案中。

camera: ^0.8.1+3
複製程式碼
  • IOS 設定

這個外掛需要 IOS 10.0 或更高版本。在 Info.plist 檔案中新增以下行來設定內容。

<key>NSCameraUsageDescription</key>
<string>Can I use the camera please?</string>
<key>NSMicrophoneUsageDescription</key>
<string>Can I use the mic please?</string>
複製程式碼
  • Android Setup

在 Android/app/build.gradle 檔案中將 Android sdk 最小版本更改為 21(或更高版本)。

minSdkVersion 21
複製程式碼

現在我們的專案設定完成了,我們可以開始編寫應用程式了。

我們將在應用程式中建立兩個螢幕。

1.CameraScreen ー此螢幕將顯示相機輸出並拍攝圖片

2.GalleryScreen ー這個螢幕將在網格檢視中顯示捕獲的圖片。

裝載攝像頭

為了顯示相機預覽,我們需要首先載入相機。為此,轉到 main.dart 檔案中的 main 函式和 runApp 上面的這些行。

WidgetsFlutterBinding.ensureInitialized(); //Ensure plugin services are initializedfinal cameras = await availableCameras(); //Get list of available cameras
複製程式碼

現在我們有了相機列表,我們需要把它們傳遞給我們的相機/螢幕。

所以,攝像機會像這樣通過

經過這一切之後,這就是 main.dart 的樣子。

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // Obtain a list of the available cameras on the device.
  final cameras = await availableCameras();
  runApp(MyApp(cameras: cameras));
}

class MyApp extends StatelessWidget {
  final List<CameraDescription> cameras;
  const MyApp({Key? key, required this.cameras}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Camera App',
      home: CameraScreen(cameras: cameras),
    );
  }
}
複製程式碼

CameraScreen

這個螢幕的佈局很簡單。在頂部我們將顯示實時相機預覽和在底部將有三個按鈕(交換相機,捕獲和顯示畫廊)。

建立一個有狀態小部件 CameraScreen。

我們將建立四個變數,

我們必須設定 selectedCamera = 0,從後置攝像頭開始。如果裝置有多於 1 個攝像頭,我們可以通過更改這個索引切換到它。

現在讓我們建立一個方法來初始化選定的相機。

在此方法中,我們將傳遞要初始化的攝像機索引。使用通過的攝像機列表,我們將載入具體的相機與解析度的選擇。

使用這個方法,我們將初始化 initState 中的後置攝像頭。

別忘了丟掉相機控制器。

  • 現在讓我們構建 UI。

為了顯示 CameraPreview,我們將使用以下程式碼。

FutureBuilder<void>(
  future: _initializeControllerFuture,
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.done) {
      // If the Future is complete, display the preview.
      return CameraPreview(_controller);
    } else {
      // Otherwise, display a loading indicator.
      return const Center(child: CircularProgressIndicator());
    }
  },
),
複製程式碼

好了,現在我們要連續顯示三個按鈕。

開關/攝像頭按鈕

首先是開關攝像頭圖示按鈕。點選這個按鈕,攝像頭應該在前後之間切換。

為此,我們將使用相同的 initializeCamera 方法,但這一次 cameraIndex 將是動態的。cameraIndex 後置攝像頭為 0,前置攝像頭為 1(如果有前置攝像頭的話)。

在點選,我們將檢查裝置是否有多個攝像頭,如果沒有,我們將顯示一個帶有訊息的 snackbar。

IconButton(
  onPressed: () {
    if (widget.cameras.length > 1) {
      setState(() {
        selectedCamera = selectedCamera == 0 ? 1 : 0;//Switch camera
        initializeCamera(selectedCamera);
      });
    } else {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: Text('No secondary camera found'),
        duration: const Duration(seconds: 2),
      ));
    }
  },
  icon: Icon(Icons.switch_camera_rounded, color: Colors.white),
),
複製程式碼

捕捉按鈕

為了顯示捕獲按鈕,我使用了一個半徑為 60 的簡單白色圓圈。點選後,我們將使用相機控制器拍攝一張照片並將其新增到 captureImages 陣列中。

GestureDetector(
  onTap: () async {
    await _initializeControllerFuture; //To make sure camera is initialized
    var xFile = await _controller.takePicture();
    setState(() {
      capturedImages.add(File(xFile.path));
    });
  },
  child: Container(
    height: 60,
    width: 60,
    decoration: BoxDecoration(
      shape: BoxShape.circle,
      color: Colors.white,
    ),
  ),
),
複製程式碼

顯示畫廊按鈕

這個按鈕非常簡單,我們將顯示從 capturedmages 陣列拍攝的最後一張圖片,當單擊時,它將導航到 GalleryScreen。

GestureDetector(
  onTap: () {
    if (capturedImages.isEmpty) return; //Return if no image
      Navigator.push(context,
        MaterialPageRoute(
          builder: (context) => GalleryScreen(
            images: capturedImages.reversed.toList())));
  },
  child: Container(
    height: 60,
    width: 60,
    decoration: BoxDecoration(
      border: Border.all(color: Colors.white),
      image: capturedImages.isNotEmpty
      ? DecorationImage(image: FileImage(capturedImages.last), fit: BoxFit.cover)
      : null,
    ),
  ),
),
複製程式碼

如您所見,GalleryScreen 接受捕獲的影像列表,因此我們可以在 gridview 中顯示它們。讓我們完成這一部分來看看應用程式的執行情況。

GalleryScreen

這是非常直接的螢幕。獲取影像列表並在 GridView 中顯示它們。

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

class GalleryScreen extends StatelessWidget {
  final List<File> images;
  const GalleryScreen({Key? key, required this.images}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Gallery'),
      ),
      body: GridView.count(
        crossAxisCount: 3,
        mainAxisSpacing: 2,
        crossAxisSpacing: 2,
        children: images
            .map((image) => Image.file(image, fit: BoxFit.cover))
            .toList(),
      ),
    );
  }
}
複製程式碼

Final Product

在構建應用程式之後,這是最終的結果。

攝像頭包也可以捕捉視訊,你可以使用 startVideoRecording,pauseVideoRecording 和 stopVideoRecording 方法來捕捉 pub.dev/packages/Ca…

這是這個專案的 Github 連結,希望對你有所幫助。

github.com/jagrut-18/f…

這個就到此為止,希望你喜歡。


© 貓哥

ducafecat.tech/

github.com/ducafecat

往期

開源

GetX Quick Start

github.com/ducafecat/g…

新聞客戶端

github.com/ducafecat/f…

strapi 手冊譯文

getstrapi.cn

微信討論群 ducafecat

系列集合

譯文

ducafecat.tech/categories/…

開源專案

ducafecat.tech/categories/…

Dart 程式語言基礎

space.bilibili.com/404904528/c…

Flutter 零基礎入門

space.bilibili.com/404904528/c…

Flutter 實戰從零開始 新聞客戶端

space.bilibili.com/404904528/c…

Flutter 元件開發

space.bilibili.com/404904528/c…

Flutter Bloc

space.bilibili.com/404904528/c…

Flutter Getx4

space.bilibili.com/404904528/c…

Docker Yapi

space.bilibili.com/404904528/c…

相關文章