Flutter

[Project] '만난지 며칠' 날짜 앱 만들기 - Chp 6. 사진 & 갤러리

모리선생 2023. 6. 8. 22:32
728x90

목표

만난지 며칠이 지났는지 확인할 수 있는 날짜 앱을 만들어보자. 이를 응용하여 100, 200, 300, 1년, 2주년까지 확인할 수 있도록 확장해보자.


본 내용을 전현직 마케터이자 현직 개발자 및 지망생이 개인공부를 하면서 배운 내용을 정리해놓은 글입니다. 해당내용에 있어서 내용상의 문의 사항 혹은 코드상에 수정사항이 발견이 되면 알려주시면 감사하겠습니다. 같이 고민해보고 수정할 수 있도록 하겠습니다.


! 알림 - 실기기 테스트 중 '계산된 날짜'불러오기가 정상적으로 작동되지 않는 경우를 발견을 했다. 이에 관련해서는 수정을 하여 새로운 코드를 업데이트 할 예정이다.

 

github (추후 공개예정)

 

메모에 중점을 두고 있는 앱이다보니 다음의 기능들을 추가 하였다.

  1. 사이드바 내 사진찍고 안드로이드 내 갤러리 불러오는 기능 추가
  2. 별도의 사진 저장가능한 갤러리 생성 (예정)

왜 사진찍기 기능을 추가 하였는가?

이유는 간단하다. 사실 image_picker라는 라이브러리를 사용해보고 싶었고, 메모앱이라면 글을 작성하는 것도 좋지만 사진을 찍을 수 있거나 해당 테마의 사진만 저장할 수 있는 갤러리가 있으면 해서 사진찍기 및 관리 기능을 추가하였다.

복잡한가?

일단 image_picker를 구현하는것은 그렇게 복잡하지 않다. 그냥 예제에 있는 것만 잘 따라오면 어느 정도는 구현이 가능하다.

 

자 그럼 시작!

pubspec.yaml에 image_picker를 추가해준다.

image_picker: ^0.8.7+5

일단은, 로그인이 되어야지 해당 페이지에 접속할 수 있도록 함수를 만들고, MemoryDate()라는 클래스가 있는 페이지로 이동할 수 있도록 구성을 하였다. 그럼 이제 사진을 찍고 저장할 수 있는 페이지를 사이드바에 추가를 하자.

 

@home_page.dart

(...)
void _handleDrawerTapDate() async {
    final currentUser = FirebaseAuth.instance.currentUser;
    if (currentUser != null) {
      await Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => MemoryDate()),
      );
    } else {
      await _showLoginDialog();
    }
  }
(...)

사이드바 버튼 부분에 이 코드를 추가 하자.

(...)

ListTile(
              title: Text('기억할 날들'),
              leading: Icon(Icons.radio_button_on),
              onTap: _handleDrawerTapDate,
            ),
            
(...)

 

이제, @memories_pics.dart를 하나 만들고, 거기에 stateful Widget을 만들자. 계속해서 상태를 확인하고 업데이트가 될 Widget이니 Stateful이 적합하다. 그 다음에 사진을 찍을지 아니면 갤러리에서 사진을 불러올지 구현하는 버튼을 만들어 보자. 궁극적으로 만들 페이지는 사진을 찍고 나서 갤러리 형태로 하나하나 저장하고 삭제할 수 있도록 하는 것이 목표지만, 공부겸 해서 한번 구현해 보았다.

 

자 이제 버튼이 포함되어 있는 페이지를 만들자. 워낙 간단해서 따로 설명을 하지는 않겠다.

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:date_counter/home_page.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_picker/image_picker.dart';

class MemoryDate extends StatefulWidget {
  const MemoryDate({super.key});

  @override
  State<MemoryDate> createState() => _MemoryDateState();
}

class _MemoryDateState extends State<MemoryDate> {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("기억하는날들"),
        ),
        body: Center(
          child: Column(
            children: [
              MaterialButton(
                  color: Colors.blue,
                  child: const Text("Pick Image from Gallery",
                      style: TextStyle(
                          color: Colors.white70, fontWeight: FontWeight.bold)),
                  onPressed: () {
                    pickImage();
                  }),
              MaterialButton(
                  color: Colors.blue,
                  child: const Text("Pick Image from Camera",
                      style: TextStyle(
                          color: Colors.white70, fontWeight: FontWeight.bold)),
                  onPressed: () {
                    takeImage();
                  }),
              showImage(),
            ],
          ),
        ));
  }
}

 

그런 다음 Image_picker를 사용하여서 카메라 및 갤러리를 불러오도록 메서드를 만들어 보자.

 

먼저, image는 gallery로 부터 이미지를 받아오도록 설정을 해놓고 image가 존재하지 않으면 갤러리를 바로 열 수 있도록 하였다.

(...)

File? image;
Future pickImage() async {
    final image = await ImagePicker().pickImage(source: ImageSource.gallery);
    if (image == null) return;

    final imageTemporary = File(image.path);

    setState(() {
      this.image = imageTemporary;
    });
  }
(...)

그다음에는 사진을 찍을 수 있도록 하는 기능을 구현하였는데 이번에는 image의 source를 카메라로 구현을 하였고, 버튼을 누르는 즉시 카메라 기능이 구현이 된다. 사진은 정말 잠시 동안 자신이 무엇을 찍었는지 보여주는 정도로만 구현이 되었다.

 

갤러리 기능은 다음에 구현을 할꺼다.

(...)

//Image 사진 찍기 사용
  Future takeImage() async {
    final image = await ImagePicker().pickImage(source: ImageSource.camera);
    if (image == null) return;

    final imageTemporary = File(image.path);

    setState(() {
      this.image = imageTemporary;
    });
  }
  
(...)

 

자 그리고 여기가 바로 방금 말한 방금 찍은 사진을 보여주는 곳이다.

//Image 보여주는 위젯
  Widget showImage() {
    return Container(
      color: Color(0xffd0cece),
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.width,
      child: Center(
          child: image == null
              ? Text('No image selected')
              : Image.file(File(image!.path))),
    );
  }

 

이렇게 하면 최종적으로는 다음과 같은 코드가 memories_pics.dart에 작성되어 있을 것이다.

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:date_counter/home_page.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_picker/image_picker.dart';

class MemoryDate extends StatefulWidget {
  const MemoryDate({super.key});

  @override
  State<MemoryDate> createState() => _MemoryDateState();
}

class _MemoryDateState extends State<MemoryDate> {
  //Image 불러오기 image_picker 사용
  File? image;
  Future pickImage() async {
    final image = await ImagePicker().pickImage(source: ImageSource.gallery);
    if (image == null) return;

    final imageTemporary = File(image.path);

    setState(() {
      this.image = imageTemporary;
    });
  }

  //Image 사진 찍기 사용
  Future takeImage() async {
    final image = await ImagePicker().pickImage(source: ImageSource.camera);
    if (image == null) return;

    final imageTemporary = File(image.path);

    setState(() {
      this.image = imageTemporary;
    });
  }

  //Image 보여주는 위젯
  Widget showImage() {
    return Container(
      color: Color(0xffd0cece),
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.width,
      child: Center(
          child: image == null
              ? Text('No image selected')
              : Image.file(File(image!.path))),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("기억하는날들"),
        ),
        body: Center(
          child: Column(
            children: [
              MaterialButton(
                  color: Colors.blue,
                  child: const Text("Pick Image from Gallery",
                      style: TextStyle(
                          color: Colors.white70, fontWeight: FontWeight.bold)),
                  onPressed: () {
                    pickImage();
                  }),
              MaterialButton(
                  color: Colors.blue,
                  child: const Text("Pick Image from Camera",
                      style: TextStyle(
                          color: Colors.white70, fontWeight: FontWeight.bold)),
                  onPressed: () {
                    takeImage();
                  }),
              showImage(),
            ],
          ),
        ));
  }
}

 

이렇게 하면 다음 처럼 앱이 만들어져 있다.

 

그럼 다음에는 최종적으로 방금 찍은 사진을 갤러리처럼 볼 수 있는 기능을 만들고 최종적으로 앱 제작을 마무리하겠다.

728x90