본문 바로가기

Flutter

[Flutter]image picker로 프로필 화면 만들기

728x90

 

 

1. image picker 라이브러리 추가

아래 명령어를 터미널에 입력한다.

 

flutter pub add image_picker

 

또는 pubspec.yaml에 직접 플러그인을 추가한다.

 

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  image_picker: ^1.0.7

 

 

2. iOS 권한 설정

ios > Runner > Info.plist 파일에 아래 코드를 추가하여 권한 설정을 한다.

 

<key>NSCameraUsageDescription</key>
<string>카메라 사용 권한 요청</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>갤러리 사용 권한 요청</string>

 

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

	... 기존 코드 ...
    
	<key>CFBundleVersion</key>
	<string>$(FLUTTER_BUILD_NUMBER)</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>NSCameraUsageDescription</key>
        <string>카메라 사용 권한 요청</string>
        <key>NSMicrophoneUsageDescription</key>
        <string>갤러리 사용 권한 요청</string>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
    
	 ... 기존 코드 ...
     
</plist>

 

<string>에는 alert 메시지창에 표시할 문구를 작성한다.

 

Android는 권한 설정을 따로 안해줘도 된다.

 

 

3. 기본 프로필 화면 구성

 

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

  @override
  State<RegisterProfile2> createState() => _RegisterProfile2State();
}

class _RegisterProfile2State extends State<RegisterProfile2> {
  // 카메라/갤러리에서 사진 가져올 때 사용
  XFile? _imageFile;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('RegisterProfile2'),
      ),

      body: Center(
        child: Column(
          children: [
            if( _imageFile == null )
              imageProfile(context)

            else
              CircleAvatar(
                radius: 80,
                backgroundImage: FileImage(File(_imageFile!.path)),
              ),
          ],
        ),
      )
    );
  }

 

 

 

4. 프로필의 카메라 버튼을 클릭하여 모달창 띄우기

 

 

Widget bottomSheet(BuildContext context) {
    return Container(
      height: 150,
      width: MediaQuery.of(context).size.width,
      margin: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                IconButton(
                  onPressed: () {
                   _pickImageFromCamera();
                  },
                  icon: Icon(Icons.camera, size: 50,),
                ),
                IconButton(
                  onPressed: () {
                    _pickImageFromGallery();
                  },
                  icon: Icon(Icons.photo_library, size: 50,),
                )
              ],
            )
          ],
        ),
      ),
    );
  }

 

 

5. XFile에 이미지 저장하기

5.1. 카메라로 촬영한 이미지 가져오기

 

Future<void> _pickImageFromCamera() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(source: ImageSource.camera);

    if( pickedFile != null ) {
      setState(() {
        _imageFile = pickedFile;
      });
    } else {
      if( kDebugMode) {
        print('이미지 선택 안 함');
      }
    }
  }

 

(iOS 시뮬레이터에서는 카메라 사용이 안된다.)

 

5.2. 갤러리에서 이미지 가져오기

 

Future<void> _pickImageFromGallery() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(source: ImageSource.gallery);

    setState(() {
      if( pickedFile != null ) {
        print(pickedFile.path);
        _imageFile = pickedFile;
      } else {
        print(('이미지를 선택하지 않음'));
      }
    });
  }

 

 

6. 전체 코드

 

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

  @override
  State<RegisterProfile2> createState() => _RegisterProfile2State();
}

class _RegisterProfile2State extends State<RegisterProfile2> {
  // (image_picker) 카메라/갤러리에서 사진 가져올 때 사용
  XFile? _imageFile;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('RegisterProfile2'),
      ),
      body: Center(
        child: Column(
          children: [
            if( _imageFile == null )
              imageProfile(context)

            else
              CircleAvatar(
                radius: 80,
                backgroundImage: FileImage(File(_imageFile!.path)),
              ),
          ],
        ),
      )
    );
  }


  Widget imageProfile(BuildContext context) {
    return Center(
      child: Stack(
        children: [
          CircleAvatar(
            radius: 80,
            backgroundImage: AssetImage('assets/default_profile.png'),
          ),
          Positioned(
            bottom: 20,
            right: 20,
            child: InkWell(
              onTap: () {
                showModalBottomSheet(
                  context: context,
                  builder: ((builder) => bottomSheet(context)),
                );
              },
              child: Icon(
                Icons.camera_alt,
              ),
            ),
          ),
        ],
      ),
    );
  }

  // 카메라 아이콘 클릭 시 띄울 모달 팝업
  Widget bottomSheet(BuildContext context) {
    return Container(
      height: 150,
      width: MediaQuery.of(context).size.width,
      margin: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                IconButton(
                  onPressed: () {
                    _pickImageFromCamera();
                  },
                  icon: Icon(Icons.camera, size: 50,),
                ),
                IconButton(
                  onPressed: () {
                    _pickImageFromGallery();
                  },
                  icon: Icon(Icons.photo_library, size: 50,),
                )
              ],
            )
          ],
        ),
      ),
    );
  }

  // 카메라에서 이미지 가져오기
  Future<void> _pickImageFromCamera() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(source: ImageSource.camera);

    if( pickedFile != null ) {
      setState(() {
        _imageFile = pickedFile;
      });
    } else {
      if( kDebugMode) {
        print('이미지 선택 안 함');
      }
    }
  }

  // 갤러리에서 이미지 가져오기
  Future<void> _pickImageFromGallery() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(source: ImageSource.gallery);

    setState(() {
      if( pickedFile != null ) {
        print(pickedFile.path);
        _imageFile = pickedFile;
      } else {
        print(('이미지를 선택하지 않음'));
      }
    });
  }
}

 

 

 

 

728x90