31. 플러터 : 앨범 + 카메라

수업도 하고 창업 준비도 하고..
그리고 놀기도 해야 하고..
하루가 길지 않음을 새삼 느끼게 된다.

플러터를 사용하는 기본적인 코드조차 머리 속에 남아있지 않음을 느끼며
이건 빨리 우재 시켜야겠다는 생각이 든다.
딥러닝 모델을 플러터에 얹으려니
카메라 사용을 먼저 처리하지 않으면 아무 것도 할 수 없어서
어쩔 수 없이 시간을 내야 했다.
머리가 너무 아프다.

앱을 구동하면 나타나는 화면.
사진도 카메라도 없기 때문에 'EMPTY' 문자열을 표시했다.
갤러리에서 사진을 선택해서 가져오면 오른쪽과 같은 모양이 된다.
이때 안드로이드 에뮬레이터 또는 아이폰 시뮬레이터에서 가져와야 하기 때문에
갤러리 또는 앨범에 사진이 들어있어야 한다.
에뮬레이터에 사진을 추가하는 방법은 다른 사이트를 참고하도록 한다.

카메라 버튼을 선택하면 촬영 모드로 들어가고
촬영한 이후에는 갤러리에서 가져오는 것과 동일하다.
실물이 훨씬 낫다.

잘 봤겠지?
이제부터 앞에서 본 것처럼 훌륭한 앱을 직접 만들어 보자.
약간 업된 것 같은 이유는
앱을 코딩했을 때는 도서관이었지만
이 글을 쓰는 곳은 바닷가이기 때문이다.
서핑하러 인구해변에 왔는데
역스웰이래나 뭐래나.. 그냥 파도가 없을 뿐이다.

프로젝트를 생성하고
pubspec.yaml 파일을 열어서 image_picker 모듈을 가져온다.
dependencies 영역 마지막에 'image_picker:'라고 쓴다.
버전을 생략하면 최신 버전을 가져온다는 뜻이다.

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2

  # 최신 버전 사용하도록 버전 명시하지 않음
  image_picker:

 

main.dart 파일을 작성한다.
앞서 봤던 것처럼 처음에 문자열을 표시했다가
사진을 선택하면 해당 사진으로 바꾼다.

우리가 할건 없고 ImagePicker 라이브러리에
갤러리(ImageSource.gallery) 또는 카메라(ImageSource.camera)를 전달하기만 하면 된다.

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';    // 앨범과 카메라 모두에 대해 작동


class ImageAndCamera extends StatefulWidget {
    @override
    ImageAndCameraState createState() => ImageAndCameraState();
}


class ImageAndCameraState extends State<ImageAndCamera> {
    // 파일 경로 문자열은 카메라에서는 에러 발생했다. image_picker 모듈에서 File 객체 반환.
    File mPhoto;
    
    @override
    Widget build(BuildContext context) {
        Widget photo = (mPhoto != null) ? Image.file(mPhoto) : Text('EMPTY');

        return Container(
            child: Column(
                children: <Widget>[
                    // 버튼을 제외한 영역의 가운데 출력
                    Expanded(
                        child: Center(child: photo),
                    ),
                    Row(
                        children: <Widget>[
                            RaisedButton(
                                child: Text('앨범'),
                                onPressed: () => onPhoto(ImageSource.gallery),  // 앨범에서 선택
                            ),
                            RaisedButton(
                                child: Text('카메라'),
                                onPressed: () => onPhoto(ImageSource.camera),   // 사진 찍기
                            ),
                        ],
                        mainAxisAlignment: MainAxisAlignment.center,
                    ),
                ],
                // 화면 하단에 배치
                mainAxisAlignment: MainAxisAlignment.end,
            ),
        );
    }

    // 앨범과 카메라 양쪽에서 호출. ImageSource.gallery와 ImageSource.camera 두 가지밖에 없다.
    void onPhoto(ImageSource source) async {
        // await 키워드 때문에 setState 안에서 호출할 수 없다.
        // pickImage 함수 외에 pickVideo 함수가 더 있다.
        File f = await ImagePicker.pickImage(source: source);
        setState(() => mPhoto = f);
    }
}

void main() {
    runApp(MaterialApp(
        home: MaterialApp(
            title: '앨범 + 카메라',
            home: Scaffold(
                appBar: AppBar(title: Text('앨범 + 카메라'),),
                body: ImageAndCamera(),
            )
        )
    ));
}