본문 바로가기
프로그래밍/Flutter & Dart

Flutter 프로필 사진 등록/변경하기

by 어느덧중반 2020. 8. 27.
반응형

Flutter 프로필 사진 등록/변경하기

이번에는 내정보의 프로필 사진 등록/변경에 대해 알아보겠다.

ImagePicker 위젯을 사용할 것이다. 사용법은 아래와 같다.

 

동작 원리

0. 화면 구성

1. Profile camera 아이콘 클릭 => 카메라로 찍기 / 갤러리에서 가져오는 모달창 생성

2. 카메라로 찍기 또는 갤러리에서 가져오기 + 변경된 내용 반영하기


 

0. 화면 구성

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: appBarWidget('Regist Profile'),
        body: Padding(
          padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
          child: ListView(
            children: <Widget>[
              imageProfile(),
              SizedBox(height: 20),
              nameTextField(),
              SizedBox(height: 20),
            ],
          )
        )
    );
  }

 

1. Profile camera 아이콘 클릭 => 카메라로 찍기 / 갤러리에서 가져오는 모달창 생성

  Widget imageProfile() {
    return Center(
      child: Stack(
        children: <Widget>[
          CircleAvatar(
            radius: 80,
            backgroundImage: _imageFile == null
              ? AssetImage('assets/profile.jfif')
              : FileImage(File(_imageFile.path)),
          ),
          Positioned(
            bottom: 20,
            right: 20,
            child: InkWell(
              onTap: () {
                // 클릭시 모달 팝업을 띄워준다.
                showModalBottomSheet(context: context, builder: ((builder) => bottomSheet()));
              },
              child: Icon(
                Icons.camera_alt,
                color: secondaryTextColor,
                size: 40,
              ),
            )
          )
        ],
      ),
    );
  }
  
  // 카메라 아이콘 클릭시 띄울 모달 팝업
  Widget bottomSheet() {
    return Container(
      height: 100,
      width: MediaQuery.of(context).size.width,
      margin: EdgeInsets.symmetric(
        horizontal: 20,
        vertical: 20
      ),
      child: Column(
        children: <Widget>[
          Text(
            'Choose Profile photo',
            style: TextStyle(
              fontSize: 20,
            ),
          ),
          SizedBox(height: 20,),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              FlatButton.icon(
                icon: Icon(Icons.camera, size: 50,),
                onPressed: () {
                  takePhoto(ImageSource.camera);
                },
                label: Text('Camera', style: TextStyle(fontSize: 20),),
              ),
              FlatButton.icon(
                icon: Icon(Icons.photo_library, size: 50,),
                onPressed: () {
                  takePhoto(ImageSource.gallery);
                },
                label: Text('Gallery', style: TextStyle(fontSize: 20),),
              )
            ],
          )
        ],
      )
    );
  }

 

2. 카메라로 찍기 또는 갤러리에서 가져오기 + 변경된 내용 반영하기

카메라로 찍거나(좌측) 갤러리에서 선택(중앙) 후 프로필 사진에 반영(우측)

// 카메라로 찍거나 갤러리에서 가져온 사진 컨트롤하기 위한 변수
PickedFile _imageFile; // 카메라/갤러리에서 사진 가져올 때 사용함 (image_picker)
final ImagePicker _picker = ImagePicker(); // 카메라/갤러리에서 사진 가져올 때 사용함 (image_picker)

...

// 프로필 사진 셋팅 부분
CircleAvatar(
  radius: 80,
  backgroundImage: _imageFile == null
    ? AssetImage('assets/profile.jfif')
    : FileImage(File(_imageFile.path)),
),

...

// 카메라 찍거나 갤러리에서 가져오는 메소드
takePhoto(ImageSource source) async {
  final pickedFile = await _picker.getImage(source: source);
  setState(() {
    _imageFile = pickedFile;
  });
}

 

전체 소스

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:my_flutter_example_app/constants/constants.dart';
import 'package:my_flutter_example_app/widgets/widgets.dart';

class RegistProfile extends StatefulWidget {
  @override
  _RegistProfileState createState() => _RegistProfileState();
}

class _RegistProfileState extends State<RegistProfile> {
  PickedFile _imageFile; // 카메라/갤러리에서 사진 가져올 때 사용함 (image_picker)
  final ImagePicker _picker = ImagePicker(); // 카메라/갤러리에서 사진 가져올 때 사용함 (image_picker)

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: appBarWidget('Regist Profile'),
        body: Padding(
          padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
          child: ListView(
            children: <Widget>[
              imageProfile(),
              SizedBox(height: 20),
              nameTextField(),
              SizedBox(height: 20),
            ],
          )
        )
    );
  }

  Widget imageProfile() {
    return Center(
      child: Stack(
        children: <Widget>[
          CircleAvatar(
            radius: 80,
            backgroundImage: _imageFile == null
              ? AssetImage('assets/profile.jfif')
              : FileImage(File(_imageFile.path)),
          ),
          Positioned(
            bottom: 20,
            right: 20,
            child: InkWell(
              onTap: () {
                showModalBottomSheet(context: context, builder: ((builder) => bottomSheet()));
              },
              child: Icon(
                Icons.camera_alt,
                color: secondaryTextColor,
                size: 40,
              ),
            )
          )
        ],
      ),
    );
  }

  Widget nameTextField() {
    return TextFormField(
      decoration: InputDecoration(
        border: OutlineInputBorder(
          borderSide: BorderSide(
            color: primaryTextColor,
          ),
        ),
        focusedBorder: OutlineInputBorder(
          borderSide: BorderSide(
            color: secondaryTextColor,
            width: 2,
          ),
        ),
        prefixIcon: Icon(
          Icons.person,
          color: primaryTextColor,
        ),
        labelText: 'Name',
        hintText: 'Input your name'
      ),
    );
  }

  Widget bottomSheet() {
    return Container(
      height: 100,
      width: MediaQuery.of(context).size.width,
      margin: EdgeInsets.symmetric(
        horizontal: 20,
        vertical: 20
      ),
      child: Column(
        children: <Widget>[
          Text(
            'Choose Profile photo',
            style: TextStyle(
              fontSize: 20,
            ),
          ),
          SizedBox(height: 20,),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              FlatButton.icon(
                icon: Icon(Icons.camera, size: 50,),
                onPressed: () {
                  takePhoto(ImageSource.camera);
                },
                label: Text('Camera', style: TextStyle(fontSize: 20),),
              ),
              FlatButton.icon(
                icon: Icon(Icons.photo_library, size: 50,),
                onPressed: () {
                  takePhoto(ImageSource.gallery);
                },
                label: Text('Gallery', style: TextStyle(fontSize: 20),),
              )
            ],
          )
        ],
      )
    );
  }

  takePhoto(ImageSource source) async {
    final pickedFile = await _picker.getImage(source: source);
    setState(() {
      _imageFile = pickedFile;
    });
  }
}
반응형

댓글