본문 바로가기
Flutter

[Flutter] 갤러리에서 이미지 가져오기(1)

by dong_seok 2023. 8. 30.

오늘은 제가 갤러리에서 이미지를 가져오고 지우는 과정에서 겪었던 많은 시행착오 과정을 얘기해보려합니다.

일단 본격적인 설명에 앞서 Flutter에서 이미지를 가져와서 사용하는데 필요한 라이브러리와 기본적인 지식들을 먼저 가볍게 말씀드리고 넘어가도록 하겠습니다.

 

먼저 제가 만들려고하는 것은 pubspec.yaml 의 assets를 설정해줘서 assets디렉토리에 저장된 이미지를 가져오는 방식이 아니라 image_picker 라이브러리를 이용해서 핸드폰 갤러리에 저장된 이미지를 가져오고 지울수 있도록 만드는것이 목표였습니다. image_picker 라이브러리의 ImagePicker().pickMultiImage()를 이용해서 한번에 여러개의 이미지를 가져오려고 했습니다. 이렇게 선택된 이미지들은 XFile 이라고 하는 클래스명으로 저장됩니다. Xfile은 현재 이미지 임시 저장위치에 대한 추상화 클래스를 말합니다. 다음과 같이 사용됩니다.

 

final ImagePicker _picker = ImagePicker();

final List<XFile>? images = await _picker.pickMultiImage();

 

pickMultiImage를 이용해서 여러개의 이미지를 한번에 가져와야 하기때문에 List<XFile> 형식으로 입력해주었습니다. 뒤에 '?'를 붙인것은 images가 null이 될 수 있다는 것을 알려줍니다.

 

인터넷에 좋은 예제가 있길래 이를 활용해 보았습니다.

 

import 'dart:io';

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

class ImagePickerScreen extends StatefulWidget {
  const ImagePickerScreen({Key? key}) : super(key: key);

  @override
  State<ImagePickerScreen> createState() => _ImagePickerScreenState();
}

class _ImagePickerScreenState extends State<ImagePickerScreen> {
  final ImagePicker _picker = ImagePicker();
  final List<XFile?> _pickedImages = [];

  // 이미지 여러개 불러오기
  void getMultiImage() async {
    final List<XFile>? images = await _picker.pickMultiImage();

    if (images != null) {
      setState(() {
        _pickedImages.addAll(images);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
          child: Column(
            children: [
              _imageLoadButtons(),
              const SizedBox(height: 20),
              _gridPhoto(),
            ],
          ),
        ),
      ),
    );
  }

  // 화면 상단 버튼
  Widget _imageLoadButtons() {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 10),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          SizedBox(
            child: ElevatedButton(
              onPressed: () => getMultiImage(),
              child: const Text('Multi Image'),
            ),
          ),
        ],
      ),
    );
  }

  // 불러온 이미지 gridView
  Widget _gridPhoto() {
    return Expanded(
      child: _pickedImages.isNotEmpty
          ? GridView(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
        ),
        children: _pickedImages
            .where((element) => element != null)
            .map((e) => _gridPhotoItem(e!))
            .toList(),
      )
          : const SizedBox(),
    );
  }

  Widget _gridPhotoItem(XFile e) {
    return Padding(
      padding: const EdgeInsets.all(2.0),
      child: Stack(
        children: [
          Positioned.fill(
            child: Image.file(
              File(e.path),
              fit: BoxFit.cover,
            ),
          ),
          Positioned(
            top: 5,
            right: 5,
            child: GestureDetector(
              onTap: () {
                setState(() {
                  _pickedImages.remove(e);
                });
              },
              child: const Icon(
                Icons.cancel_rounded,
                color: Colors.black87,
              ),
            ),
          )
        ],
      ),
    );
  }
}

 

앱을 실행하면

 

 

이런 버튼이 하나 나오고 클릭하면 갤러리로 이동해서 이미지를 선택할 수 있습니다. 

 

 

이미지가 선택되면 GridView를 이용해서 화면에 보여주었습니다. 이때 들었던 생각은 이미지가 선택되면 위에 있는 버튼을 없애는게 훨씬 깔끔하겠다는 생각이 들었습니다. 그래서 if문을 사용해서 

 

children: [
  if(_pickedImages==null)
    _imageLoadButtons()
  else
    _gridPhoto(),
],

 

이렇게 코드를 바꿔주려고 하였습니다. 그런데 

 

 

null이 될 수 없다는 문구가 나오고 if문이 안돼서 당황했습니다. 찾아보니 _pickedImages는 List로 선언되었고 초기화도 해줬기 때문에 List 자체는 null이 될 수 없어서 이런 경고문구가 뜬 것이었습니다. 인덱스를 지정해주면 null이 정상적으로 작동했습니다.( ex) _pickedImages[0]==null ) 하지만 제가 사용하려는 것은 하나하나의 인덱스가 아니라 리스트 자체였기 때문에 어떻게 해야할지 많이 찾아봤습니다. 그러다 isEmpty를 사용하면 된다는 것을 알게됐고 

 

children: [
  if(_pickedImages.isEmpty)
    _imageLoadButtons()
  else
    _gridPhoto(),
],

 

이렇게 코드를 수정하였습니다. 그랬더니

이미지 선택후 버튼이 사라진 것을 볼 수 있습니다!

 

참고자료

https://dalgoodori.tistory.com/38

'Flutter' 카테고리의 다른 글

[Flutter] 오류 (Error Opening Emulator)  (0) 2023.08.31
[Flutter] 갤러리에서 이미지 가져오기(2)  (0) 2023.08.30
[Flutter] Today 날짜 가져오기  (0) 2023.08.27
[Flutter] http 통신(Post)  (0) 2023.08.26
[Flutter] Listview.builder  (0) 2023.08.22

댓글