티스토리 뷰
IOS Beginner | 회원가입 page 만들기 UIPageViewController, UIImagePickerController
글그리 2020. 12. 26. 21:31회원가입 페이지를 각 항목을 입력하는 화면으로 나눠서 만들고 싶어서 UIPageViewController라는 ViewController를 사용하려 했지만 막상 공부를 해 보니 예상했던 기능과는 조금 다른 용도로 사용하는 것 같다.
먼저 만들고자 하는 회원가입 절차를 생각해보자. 지금까지 만든 회원 정보 중에 처음에 사용자가 입력할 수 있는 부분은 2가지다. 이름은 텍스트로 입력을 받고 프로필 사진은 현재 라이브러리 또는 카메라로 사진을 선택할 수 있도록 한다. 이렇게 입력받은 2개의 데이터를 서버에 있는 데이터베이스에 등록하고 다음번에 로그인 할 때 이 데이터를 불러와서 화면에 그릴 수 있도록 한다.
이미 firebase로 연동을 했기 때문에 정상적으로 회원가입을 하려면 token이 필요하다. 하지만 테스트를 할 때 마다 구글 아이디를 새로 만들 수는 없기 때문에 테스트 데이터를 사용할 수 있도록 흐름을 조금 수정한다.
UIPageViewController
PageViewController는 ViewController를 화면에 보여주고, swipe 동작으로 다음 또는 이전 ViewController로 이동할 수 있다. setViewControllers는 지금 화면에 보여야 하는 view controller를 설정한다. 함수 이름에 s가 붙어 있고, 실제로 매개변수는 [UIViewController]라는 배열을 받는다. iPad UI의 경우 가로로 두었을 때 2개 이상의 page가 보일 수 있기 때문인 것 같다.
class SignUpPageController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
let page = UIViewController()
self.setViewControllers([page], direction: .forward, animated: false, completion: nil)
}
iPhone은 기본적으로 page가 하나씩 밖에 보이지 않지만 위처럼 배열로 만들어서 전달해야 한다. direction은 방향을 뜻하며, viewControllers로 바뀔 때 animation 방향을 정할 수 있다. 특별히 page라는 view를 사용하는게 아니라 ViewController를 transition시키면서 화면에 보여주는 기능을 제공하는 controller인 것 같다.
회원가입의 경우 이름을 입력할 수 있는 ViewController, 프로필 이미지를 선택할 수 있는 ViewController를 page로 넘기면서 처리하도록 만들 것이기 때문에 이러한 ViewController를 저장할 수 있는 배열을 선언한다. UIViewController를 상속 받아서 새로운 ViewController를 정의하는 것이 좋은데, PageViewController의 dataSource에서 처리하기 쉽도록 index를 추가하기 위함이다.
dataSource는 사용자가 스크롤 조작으로 page를 넘길 때 또는 setViewController 등으로 page의 전환이 일어나야 할 때 다음 또는 이전 화면에 보여질 ViewController를 질의하는 함수들을 제공하는데, 이 함수들과 SignUpPageController에 저장한 SignUpViewController배열을 참고해서 따라 다음 또는 이전 page로 사용 될 SignUpViewController를 제공할 수 있다.
extension SignUpPageController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let vc = viewController as? SignUpViewController, vc.index > 0 else {
return nil
}
return signUpViews[vc.index - 1]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let vc = viewController as? SignUpViewController, vc.index < signUpViews.count - 1 else {
return nil
}
return signUpViews[vc.index + 1]
}
}
signUpViews 배열은 회원가입이 진행됨에 따라 다음 SignUpViewController를 추가하면서 점점 크기가 커지도록 만들었다. 이러한 방법은 PageViewController의 기능과는 상관없는 내용이기 때문에 구체적인 코드는 생략하고 간략하게 그림으로 표현하면 이렇게 된다.
각 page(SignUpViewController)는 SignUpPageController에서 관리하기 때문에 사용자가 각각 입력한 데이터들은 SignUpPageController가 모두 저장하도록 만들었다.
UIImagePickerController
IOS는 windows나 OSX처럼 파일 탐색기, Finder가 없다. 대신 현재 기기에 저장된 사진 파일들을 볼 수 있는 PhotoLibrary라는 제한된 파일 시스템을 제공한다. 이 파일 시스템에 접근할 수 있는 controller가 바로 UIImagePickerController이다.
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
present(picker, animated: true, completion: nil)
일반적인 ViewController와 같이 present를 통해 화면에 보이게 할 수 있다.
UIImagePickerController는 총 3가지 sourceType이 있는데, 이미 저장된 라이브러리에 접근하는 type, 카메라로 새롭게 사진은 찍어서 source로 사용할 수 있는 type이 있다. 단, 대부분 IOS 기기가 카메라를 가지고 있지만 시뮬레이터의 경우 카메라 기능을 지원하지 않으며, 예외 상황이 생길 수 있기 때문에 해당 sourceType이 사용 가능한지 미리 검사를 하고 사용해야 한다.
if UIImagePickerController.isSourceTypeAvailable(.camera) {
picker.sourceType = .camera
} else {
picker.sourceType = .photoLibrary
}
delegate는 PickerController에서 사용자가 어떤 사진 파일을 선택했을 때, 취소했을 때 등 이벤트를 처리할 수 있는 대리자로 UINavigationViewContrllerDelegate와 같이 사용해야 한다. delegate를 초기화하지 않으면 사진을 선택했을 때 Controller를 dismiss 시키는 기본 delegate를 사용한다.
extension SignUpProfileImageController: UIImagePickerControllerDelegate, UINavigationViewControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
profileImage.image = image
profileImage.contentMode = .scaleToFill
}
self.dismiss(animated: true, completion: nil)
}
}
이미지를 선택했을 때 선택한 이미지에 대한 정보를 info라는 dictionary로 넘겨주는데, ImagePicker이지만 동영상이나 live photo 등 다른 미디어를 선택할 수도 있기 때문에 그에 맞는 다양한 정보가 들어있다. 위 코드에서는 editedImage를 가지고 와서 프로필 이미지로 사용했다.
이럴거면 UIMediaPicker라고 이름을 지었으면 더 괜찮지 않았을까?
delegate를 새롭게 정의해 주었기 때문에 dismiss도 직접 호출해야 한다.
Result
디자인에 따라 달라질 수 있는 부분들은 빼고 UIPageViewController, UIImagePickerController를 사용하는 부분만 빼서 정리했다. 이름을 입력하는 page, 프로필 사진을 선택하는 page 이렇게 두개의 page를 관리하고, 프로필 사진을 선택하는 page에서 UIImagePickerController로 사진을 선택할 수 있도록 만들었다.
시뮬레이터에서 구동했기 때문에 photoLibrary만 접근할 수 있다.
library를 선택하는 부분은 UIAlertController로 만들었는데, 위처럼 actionSheet로 그릴 경우 constraint error가 발생한다. 찾아보니 IOS 12.2 ~ 14.2 까지 있는 버그라고 한다.
'Programming > IOS' 카테고리의 다른 글
iOS Expert | UICollectionView pinterest layout 만들어보기 (1) | 2020.12.31 |
---|---|
IOS Beginner | UITableView tutorial dynamic height (0) | 2020.12.30 |
IOS Beginner | storyboard 탈출 (0) | 2020.12.17 |
iOS Expert | Firebase GoogleSignIn 연동 (0) | 2020.12.15 |
iOS Expert | 서버에 저장된 이미지로 view update (0) | 2020.12.13 |
- Total
- Today
- Yesterday
- SwiftUI
- 수학
- ue4
- scala
- 운영체제
- 국내여행
- C
- JSP
- ios
- 데이터베이스
- C++
- 알고리즘
- Git
- Java
- rxswift
- game
- 드라마
- SHADER
- database
- swift
- mongoDB
- 자료구조
- Cocos2d-x
- OS
- C/C++
- DesignPattern
- Spring
- SOCKET
- machine learing
- winsock
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |