[Flutter] 폰에 저장된 이미지 가져오기

2023. 9. 22. 22:40·Web & Android/Flutter

image_picker 설치와 셋팅

  • pubspec.yaml 파일에 코드 추가 후 pub get
  dependencies:
    image_picker: ^0.8.4+4
  • ios/Runner/info.plist 파일에 코드 추가
    • 하단에 추가
    • 사용자에게 허락 팝업 띄울 때 보이는 글자들
  <key>NSPhotoLibraryUsageDescription</key>
  <string>사진첩좀 써도 됩니까</string>
  <key>NSCameraUsageDescription</key>
  <string>카메라좀 써도 됩니까</string>
  <key>NSMicrophoneUsageDescription</key>
  <string>마이크 권한좀 제발</string>
  • dart 파일 맨 위에 import 추가
import 'package:image_picker/image_picker.dart';
import 'dart:io';

 

image_picker 사용법

onPressed: () async {
  var picker = ImagePicker();
  var image = await picker.pickImage(source: ImageSource.gallery);
}

⇒ 이미지 선택 화면 뜨는 코드

  • picker.pickImage(source: ImageSource.camera);
    • 사진 선택하는 갤러리 말고 카메라를 띄워줌
  • picker.pickVideo(source: ImageSource.gallery);
    • 비디오 선택 화면이 뜸
  • picker.pickMultiImage(source: ImageSource.gallery);
    • 여러 이미지 선택이 가능

→ 고른 이미지 사이즈, 화질 조정도 가능

→ photofilters 패키지 설치하면 이미지에 필터 씌울 수 있음

 

선택한 이미지 다루기

  • 이미지는 용량이 크므로 변수에 저장하기보단 이미지의 경로만 가져와서 변수에 저장하고 사용하는게 일반적임
onPressed: () async {
  var picker = ImagePicker();
  var image = await picker.pickImage(source: ImageSource.gallery);
   if (image != null) {  // 선택 안하면 null이므로 체크
    setState((){
      userImage = File(image.path);
    });
  }
}

 

선택한 이미지를 위젯으로 보여주기

  • Image.file(userImage) 사용하면 됨
    - 이미지 파일 경로를 넣으면 이미지로 보여주는 위젯
    - userImage 변수는 MyApp() 위젯 안에 있으므로 Upload로 변수를 보내서 사용

전체 코드

import 'package:flutter/material.dart';
import './style.dart' as style;
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/rendering.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';

void main() {
  runApp(
      MaterialApp(
      theme: style.theme,
      home: MyApp()
  ));
}

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

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

class _MyAppState extends State<MyApp> {
  var tab = 0;  // 1. 현재 상태 저장
  var list = [1, 2, 3];
  var map = {'name':'john', 'age':20};
  var data = [];
  var userImage;

  addData(a) {
    setState(() {
      data.add(a);
    });
  }

  getData() async {
    var result = await http.get(Uri.parse('https://codingapple1.github.io/app/data.json'));

    var result2 = jsonDecode(result.body);
    setState(() {
        data = result2;
    });

  }

  @override
  void initState() {
    super.initState();
    getData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text('Instagram'),
          actions: [
            IconButton(
              icon: Icon(Icons.add_box_outlined),
              onPressed: () async {
                var picker = ImagePicker();
                var image = await picker.pickImage(source: ImageSource.gallery);
                if(image != null)  {
                  setState(() {
                    userImage = File(image.path);
                  });
                }

                Navigator.push(context,
                  MaterialPageRoute(builder: (c) => Upload( userImage : userImage) )
                );
              },
              iconSize: 30,
            )
          ]),
      body: [Home(data : data, addData : addData), Text('샵페이지')][tab],  // 2. state에 따라 tab 보이는 상태 변경
      bottomNavigationBar: BottomNavigationBar(
        showSelectedLabels: false,
        showUnselectedLabels: false,
        onTap: (i){
          setState(() {
            tab = i;
          });
        },
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: '홈'),
          BottomNavigationBarItem(icon: Icon(Icons.shopping_bag_outlined), label: '샵')
        ],
      ),
    );
  }
}

class Home extends StatefulWidget {
  const Home({Key? key, this.data, this.addData}) : super(key: key);
  final data, addData;

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {

  var scroll = ScrollController();

  getMore() async {
    var result = await http.get(Uri.parse('https://codingapple1.github.io/app/more1.json'));
    var result2 = jsonDecode(result.body);

    widget.addData(result2);
  }

  @override
  void initState() {
    super.initState();
    scroll.addListener(() {   // 스크롤바 높이 측정 코드
      if(scroll.position.pixels == scroll.position.maxScrollExtent) {
        getMore();
      }
    });
  }

  @override
  Widget build(BuildContext context) {

    if (widget.data.isNotEmpty) {
      return ListView.builder(
          itemCount: widget.data.length,
          controller: scroll,
          itemBuilder: (c, i) {
            return Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Image.network(widget.data[i]['image']),
                Container(
                  constraints: BoxConstraints(maxWidth: 600),
                  padding: EdgeInsets.all(20),
                  width: double.infinity,
                  child: Column(
                    children: [
                      Text('좋아요 ${widget.data[i]['likes'].toString()}'),
                      Text(widget.data[i]['date']),
                      Text(widget.data[i]['content'])
                    ],
                  ),
                )
              ],
            );
          }
      );
    } else {
      return Text('로딩중임');
    }
  }
}

class Upload extends StatelessWidget {
  const Upload({Key? key, this.userImage}) : super(key: key);
  final userImage;

  @override

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Image.file(userImage),
            Text('이미지업로드화면'),
            TextField(),
            IconButton(
                onPressed: (){
                  Navigator.pop(context);
                },
                icon: Icon(Icons.close)
            ),
          ],
        )
    );
  }
}

숙제

→ 발행 버튼 누르면 유저가 입력한 글과 사진 게시물로 보여주기

  1. 우선 발행 버튼 하나 만들고
  2. Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( actions: [ IconButton(onPressed: (){}, icon: Icon(Icons.send)) ]), (생략)
  3. 유저가 입력한 글과 사진을 MyApp 안에 state에 저장해둠
    • 유저가 글 입력하면 userContent에 저장되게 만들기
      (Upload페이지)
      
      TextField(onChanged: (text){ setUserContent(text); })
  4. class _MyAppState extends State<MyApp> { var tab = 0; var data = []; var userImage; var userContent; setUserContent(a){ setState(() { userContent = a; }); } (생략)
  5. 발행 버튼 누르면 var data = [] 에 게시물 데이터 하나 추가
    • 게시물 데이터엔 유저가 선택한 사진과 글이 들어가면 됨
    • list 맨 앞부분에 자료 추가하고 싶으면 data.insert(0, 자료) 사용
    class _MyAppState extends State<MyApp> {
    
      var tab = 0;
      var data = [];
      var userImage;
      var userContent;
    
      addMyData(){
        var myData = {
          'id': data.length,
          'image': userImage,
          'likes': 5,
          'date': 'July 25',
          'content': userContent,
          'liked': false,
          'user': 'John Kim'
        };
        setState(() {
          data.insert(0, myData);
        });
      }
    
    (생략)
    • Upload 페이지의 발행 버튼 누르면 저 함수 실행
      Scaffold(
            resizeToAvoidBottomInset: false,
            appBar: AppBar( actions: [
              IconButton(onPressed: (){ addMyData(); }, icon: Icon(Icons.send))
            ]),
      (생략)
  6. 이상한 건 if문으로 예외 처리
    - 3번까지 하고 돌리면 콘솔창에 에러남
    - type '_File' is not a subtype of type 'String’
    - 이미지 보여줄 때 Image.network() 여기에 ‘https://어쩌구’ 이런 거 넣어서 보여주고 있는데 사용자가 선택한 건 File 타입이기 때문에 타입 에러 발생
    - 그래서 삼중 연산자를 통해 이미지 경로가 문자이면 무엇을, 그에 아니라면 이것을 보여달라고 코드 구현
  7. Image.network(widget.data[i]['image']) // -> 이렇게 변경 widget.data[i]['image'].runtimeType == String ? Image.network(widget.data[i]['image']) : Image.file(widget.data[i]['image']),
저작자표시 비영리 변경금지 (새창열림)

'Web & Android > Flutter' 카테고리의 다른 글

[Flutter] 위젯 클릭 - GestureDetector  (0) 2023.09.22
[Flutter] DB 없이 데이터 저장하기 - Shared preferences  (1) 2023.09.22
[Flutter] 페이지 나누기 - 라우터 사용 (/)  (0) 2023.09.22
[Flutter] 페이지 나누기 - Navigator  (0) 2023.09.22
[Flutter] 페이지 나누기 - Tab  (0) 2023.09.22
'Web & Android/Flutter' 카테고리의 다른 글
  • [Flutter] 위젯 클릭 - GestureDetector
  • [Flutter] DB 없이 데이터 저장하기 - Shared preferences
  • [Flutter] 페이지 나누기 - 라우터 사용 (/)
  • [Flutter] 페이지 나누기 - Navigator
woojin._.
woojin._.
여러가지 개발을 해보며 발생하는 이야기들에 대한 블로그입니다:)
  • woojin._.
    Jin's Dev Story
    woojin._.
  • 전체
    오늘
    어제
    • 분류 전체보기 (829)
      • Tools (25)
        • eGovFrame (3)
        • GeoServer (3)
        • QGIS (2)
        • LabelImg (2)
        • Git (6)
        • GitHub (1)
        • Eclipse (7)
        • Visual Studio (1)
      • Web & Android (121)
        • SpringBoot (37)
        • Three.js (2)
        • Spring Data JPA (9)
        • 스프링 부트 쇼핑몰 프로젝트 with JPA (25)
        • Thymeleaf (4)
        • Spring Security (15)
        • Flutter (29)
      • Programming Language (61)
        • JAVA (27)
        • JavaScript (14)
        • Dart (2)
        • Python (15)
        • PHP (3)
      • Database (43)
        • PostgreSQL (32)
        • MYSQL (7)
        • Oracle (3)
        • MSSQL (1)
      • SERVER (17)
        • TCP_IP (3)
        • 리눅스 (7)
        • AWS (7)
      • Coding Test (445)
        • 백준[JAVA] (108)
        • 프로그래머스[JAVA] (260)
        • 알고리즘 고득점 Kit[JAVA] (3)
        • SQL 고득점 Kit[ORACLE] (74)
      • CS 지식 (49)
        • [자료구조] (14)
        • [네트워크] (12)
        • [데이터베이스] (10)
        • [알고리즘] (9)
        • [운영체제] (4)
      • 기타 (6)
      • 자격증 & 공부 (62)
        • 정보처리기사 (2)
        • SQLD (6)
        • 네트워크관리사 2급 (5)
        • 리눅스마스터 1급 (44)
        • 리눅스마스터 2급 (1)
        • ISTQB (3)
        • 시스템보안 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    리눅스마스터
    CS
    스프링 부트 쇼핑몰 프로젝트 with JPA
    자바
    Oracle
    데이터베이스
    programmers
    Flutter
    프로그래머스
    DB
    pcce 기출문제
    JPA
    리눅스마스터 1급
    시큐리티
    플러터
    스프링부트
    spring
    백준
    postgresql
    스프링
    Java
    데이터
    Spring Security
    CS지식
    리눅스
    Linux
    python
    backjoon
    springboot
    baekjoon
  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
woojin._.
[Flutter] 폰에 저장된 이미지 가져오기
상단으로

티스토리툴바