[flutter] 이미지 가져오기

KoEunseo·2023년 10월 5일
1

flutter

목록 보기
17/45

1. image picker 다운받기

pub dev

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^1.0.4

2. 권한 설정하기

ios: Info.plist

관련 공식문서
key와 string이 한 쌍이다.
key는 받을 권한, string은 권한을 요청할 때 유저에게 보여줄 디스크립션.

	<key>NSPhotoLibraryUsageDescription</key>
	<string>This app required NSPhotoLibraryUsageDescription permission</string>
	<key>NSCameraUsageDescription</key>
	<string>This app required NSCameraUsageDescription permission</string>
	<key>NSMicrophoneUsageDescription</key>
	<string>This app required NSMicrophoneUsageDescription permission</string>

android: AndroidManifest.xml

범위 지정 저장소를 사용하도록 업데이트되었으므로 더 이상 AndroidManifest.xml의 태그 android:requestLegacyExternalStorage="true"에 속성을 추가할 필요가 없습니다 .<application>image_picker

관련 공식문서
따로 xml파일에 권한 설정을 하지 않아도 되는 모양.

이미지 라이브러리에 접근하기

ImagePicker를 생성해서 사용하면 된다.

1. 이미지 피커 생성

var imagePicker = ImagePicker();

2. 이미지피커 핸들링

() async {
  var image =
  await imagePicker.pickImage(source: ImageSource.gallery);
  if (image != null) {
  print('이미지가 선택되었습니다.');
  selectedImage = image;
  setState(() {});
} else {
  print('아무것도 선택하지 않았습니다.');
}

3. 선택된 이미지 사용

if (selectedImage != null) //!를 사용해 이미지가 있다고 단언하기 때문에 if문으로 검사를 먼저 해줌
  CircleAvatar(
    radius: 50,
    backgroundImage: AssetImage(
    selectedImage!.path, //path
  ),
),

전체 코드

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

void main() {
  runApp(const MyApp());
}

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

  
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  XFile? selectedImage;

  
  Widget build(BuildContext context) {
    var imagePicker = ImagePicker();
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              if (selectedImage != null)
                CircleAvatar(
                  radius: 50,
                  backgroundImage: AssetImage(
                    selectedImage!.path,
                  ),
                ),
              TextButton(
                onPressed: () async {
                  var image =
                      await imagePicker.pickImage(source: ImageSource.gallery);
                  if (image != null) {
                    print('이미지가 선택되었습니다.');
                    selectedImage = image;
                    setState(() {});
                  } else {
                    print('아무것도 선택하지 않았습니다.');
                  }
                },
                child: const Text('Click me'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

안드로이드의 경우 에러가 나는 경우가 있는 듯 하다.

포토네컷 실습

요구사항

  • Requirements
    • 네모 컷 위젯을 한 번 탭하면 이미지를 선택할 수 있도록 갤러리를 불러옵니다.
    • 이 때 이미지를 선택할 경우 해당 네모 컷 위젯에 선택된 이미지로 대체됩니다.
      • 다시 한 번 클릭해서 이미지를 바꿀 수 있습니다.
    • 네모 컷 위젯을 더블클릭하면 기존의 이미지가 없어지도록 합니다.
    • 최대한 코드를 줄여볼 수 있도록 합니다.

main.dart

for문을 써서 4개의 Photo가 나오도록 하려 했으나 에러가 발생.
List.generate를 사용하는 것으로 수정했다.

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

void main() {
  runApp(const MyApp());
}

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

  
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  XFile? selectedImage;

  
  Widget build(BuildContext context) {
    var imagePicker = ImagePicker();
    return MaterialApp(
      theme: ThemeData.dark(),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('포토네컷'),
          elevation: 0,
          backgroundColor: Colors.transparent,
        ),
        body: Center(
          child: Column(
            children: List.generate(
              4,
              (index) => Photo(
                imagePicker: imagePicker,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Photo.dart

처음엔 이미지를 부모컴포넌트에서 리스트로 관리해서 photo로 하나씩 전달하도록 하려고 했으나 그냥 각 위젯에서 이미지를 각자 관리하는 게 간단할 것 같아서 이미지피커를 부모컴포넌트에서 받아오도록 했다.

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

class Photo extends StatefulWidget {
  const Photo({
    super.key,
    required this.imagePicker,
  });
  final ImagePicker imagePicker;

  
  State<Photo> createState() => _PhotoState();
}

class _PhotoState extends State<Photo> {
  XFile? selectedImg;
  
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: GestureDetector(
        onTap: () async {
          var image =
              await widget.imagePicker.pickImage(source: ImageSource.gallery);
          if (image != null) {
            selectedImg = image;
            setState(() {});
          }
        },
        onDoubleTap: () {
          if (selectedImg != null) {
            selectedImg = null;
            setState(() {});
          }
        },
        child: Container(
          width: 300,
          height: 150,
          color: Colors.black54,
          child: selectedImg != null
              ? Image.asset(
                  selectedImg!.path,
                  fit: BoxFit.cover,
                )
              : null,
        ),
      ),
    );
  }
}

포토네컷 시연영상


포토네컷 해설

Expanded로 감싸면 각 container가 같은 크기를 갖는다.

언더바: class 내에서만 사용하는 private한 변수

container의 decoration으로 decorationImage를 할당할 수 있다.

Container(
  decoration: BoxDecoration(
    image: DecorationImage(image: AssetImage('이미지경로')
    )
  )
)

safeArea로 UI화면에 짤리지 않도록 할 수 있다.

XFile List

List<XFile?> images = [null, null, null, null]

map에서 index 사용하는 법!!

이거 정말로 궁금했고 필요했다... 플러터에서는 map할때 두번째 인자가 index가 아니더라...
List와 map 사이에 asMap().entries를 껴서 사용한다.
key가 index임!

images.asMap().entries.map(el => Photo(images[e.key]))
profile
주니어 플러터 개발자의 고군분투기

0개의 댓글