일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 안드로이드 숏컷
- swift sms
- silent push
- 스위프트 테이블 뷰 셀
- 앱 백그라운드 푸시 데이터 저장
- swift autolayout
- 스위프트 앨범
- 안드로이드 FCM
- 안드로이드 에러
- swift 문자
- NotificationService Extension
- Flutter NativeView
- flutter rotate
- 푸시 데이터 저장
- 노티피케이션 익스텐션
- 스위프트 푸시
- Swift flutterview
- 안드로이드 바로가기
- 안드로이드 앨범
- 스위프트
- Flutter UIKitView MethodChannel
- 스위프트 카메라
- 스위프트 웹뷰
- 스위프트 UserDefaults
- flutter 회전
- 앱 꺼졌을 때 푸시 데이터 저장
- native flutter view
- FlutterView MethodChannel
- 플러터 뷰 컨트롤러
- Swift flutterviewcontroller
- Today
- Total
Things take time
[SWIFT] UIPageViewController 사용하기 (하나의 뷰 컨트롤러) 본문
[UIPageViewController]
안드로이드에 있는 뷰 페이저(View Pager)의 대응 기능이다.
여러 개의 뷰를 페이징 처럼 넘기면서 볼 때 사용한다.
옛날 포스팅에는 여러개의 뷰 컨트롤러를 두고 해당 뷰 컨트롤러를 페이징하는 기본적인 페이지 뷰 컨트롤러를 사용했지만, 이번에 사용할 것은 하나의 뷰 컨트롤러를 재활용해서 사용할 것이다.
기본 완성화면은 다음과 같다.
여러 개의 이미지 들을 페이지로 넘기면서 각 이미지들을 다운받을 수 있도록 한다.
[준비물]
필요한 뷰 컨트롤러는 3개다. UIPageViewController 프로토콜을 상속받을 컨트롤러, 실제 재활용될 뷰 컨트롤러, 그리고 껍데기로 가져다 쓸 UIPageViewController
직접 뷰 컨트롤러를 PageViewController를 컴포넌트로 사용해도 되는데, 나같은 경우에는 위의 화면처럼 다운로드 버튼, X버튼을 넣을거라 일반 뷰 컨트롤러를 사용했다. 물론 페이저 뷰 컨트롤러 베이스로 직접 UI를 코드로 넣어도 되지만 귀찮으니까!
기본 뷰 컨트롤러 1 (위 아래 이미지 뷰를 제외한 가운데 뷰를 페이지 뷰 컨트롤러를 상속받게 할 것), PageMainViewController.swift 파일로 연결된다.
기본 뷰 컨트롤러2 각 페이지 뷰 컨트롤러의 기본이 되는 뷰 컨트롤러, 이미지 뷰 하나를 오토레이아웃으로 화면을 다 잡는다.
스토리보드 네임은 PageContentViewController 및 스위프트 파일 명도 동일하다.
그리고 기본 UIPageViewController, 스토리보드 네임은 PageViewController
[소스 코드]
1. PageContentViewController
import UIKit class PageContentViewController: UIViewController { @IBOutlet weak var ivImage: UIImageView! var index: Int! var imgStr: String! override func viewDidLoad() { super.viewDidLoad() self.ivImage.image = UIImage(named: imgStr) } }
재활용할 기본 뷰, 이미지 뷰 하나와 index를 넣는다. index는 현재 보여줄 이미지들과 매치시킬 때 사용한다.
2. PageMainViewController
import UIKit class PageMainViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { @IBOutlet weak var vMain: UIView! @IBOutlet weak var ivClose: UIImageView! @IBOutlet weak var ivDown: UIImageView! var pageVC: UIPageViewController! var pageImages: Array! var currentIdx:Int = 0 var chooseIdx = 0 override func viewDidLoad() { super.viewDidLoad() self.pageImages = ["img01" , "img02" , "img03" , "img04" , "img05"] self.pageVC = UIStoryboard(name: "Popup", bundle: nil).instantiateViewController(withIdentifier: "PageViewController") as? UIPageViewController self.pageVC.dataSource = self self.pageVC.delegate = self let startVC = self.viewControllerAtIndex(index: chooseIdx) as PageContentViewController let viewControllers = NSArray(object: startVC) self.pageVC.setViewControllers(viewControllers as? [UIViewController] , direction: .forward, animated: true, completion: nil) self.addChild(self.pageVC) self.vMain.addSubview(self.pageVC.view) // AutoLayout self.pageVC.view.translatesAutoresizingMaskIntoConstraints = false self.vMain.addConstraint(NSLayoutConstraint(item: self.pageVC.view, attribute: .top, relatedBy: .equal, toItem: self.vMain, attribute: .top, multiplier: 1, constant: 0)) self.vMain.addConstraint(NSLayoutConstraint(item: self.pageVC.view, attribute: .left, relatedBy: .equal, toItem: self.vMain, attribute: .left, multiplier: 1, constant: 0)) self.vMain.addConstraint(NSLayoutConstraint(item: self.pageVC.view, attribute: .bottom, relatedBy: .equal, toItem: self.vMain, attribute: .bottom, multiplier: 1, constant: 0)) self.vMain.addConstraint(NSLayoutConstraint(item: self.pageVC.view, attribute: .right, relatedBy: .equal, toItem: self.vMain, attribute: .right, multiplier: 1, constant: 0)) ivClose.isUserInteractionEnabled = true ivClose.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(ivCloseClicked))) ivDown.isUserInteractionEnabled = true ivDown.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(ivDownClicked))) } @objc func ivCloseClicked(){ self.dismiss(animated: true, completion: nil) } @objc func ivDownClicked(){ // 다운로드 로직 } func viewControllerAtIndex (index : Int) -> PageContentViewController { guard let vc = UIStoryboard(name: "Popup", bundle: nil).instantiateViewController(withIdentifier: "PageContentViewController") as? PageContentViewController else { return PageContentViewController() } vc.index = index vc.imgStr = self.pageImages[index] return vc } // 현재 페이지 로드가 끝났을 때 func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { if completed { if let currentViewController = pageVC.viewControllers![0] as? ImageContentViewController { currentIdx = currentViewController.index } } } // 현재 페이지 뷰의 이전 뷰를 미리 로드 func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { let vc = viewController as! PageContentViewController var index = vc.index as Int if( index == 0 || index == NSNotFound) { return nil } index -= 1 return self.viewControllerAtIndex(index: index) } // 현재 페이지 뷰의 다음 뷰를 미리 로드 func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { let vc = viewController as! PageContentViewController var index = vc.index as Int if( index == NSNotFound) { return nil } index += 1 if(index == self.pageImages.count){ return nil } return self.viewControllerAtIndex(index: index) } // 인디케이터 개수 func presentationCount(for pageViewController: UIPageViewController) -> Int { return self.pageImages.count } // 인디케이터 초기 선택 값 func presentationIndex(for pageViewController: UIPageViewController) -> Int { return chooseIdx } }
주석만 봐도 이해하기 쉬울 것이다.
일단 pageVC라는 변수에 페이지뷰 컨트롤러를 가져와서 넣고, dataSource를 연결한다. 기본적인 사용에는 delegate가 필요 없다.
그리고 viewControllerAtIndex라는 함수에 초기 값을 넣어주고 이미지를 넣는다.
setViewControllers를 통해 페이지 뷰 안에 들어가는 실제 컨텐츠 뷰를 세팅한다. (페이지 뷰 컨트롤러의 기본 세팅 문법)
그리고 UI, Autolayout설정으로 viewDidLoad() 마무리.
pageViewController(didFinishAnimation)이란 함수를 통해 현재 몇 번째 이미지가 로드 되었는지를 알 수 있다.(하단 인디케이터 위치), delegate소속함수
index 세팅은 소스를 보면 이해가 될 것이고, 마지막 presentationIndex를 통해 초기 선택 값을 설정할 수 있다. 이 예제에서는 이미지를 5개로 고정시켰고, 기본 img01부터 로드되도록 했기 때문에 필요는 없다.
그러나 실제 현업 소스에서는 이미지 리스트에서 한 이미지를 선택하고, 그 이미지가 전체 이미지들 사이에서 몇 번째인지, 기준 값을 세팅해줘야하는 로직이 필요하기 때문에 따로 넣은 소스다.
pageImages도 이전 뷰 에서 넘겨받아야 할 것이고, 실제 PageContentView도 이미지 뷰 하나만 사용할 수도 있지만, 이미지가 실제 저장되지 않았다면 다운로드 받도록 하는 UI, ProgressBar등 여러 로직들도 포함되어야 한다.
이 예제는 말 그대로 기본만을 담고 있기 때문에, 이것을 바탕으로 응용해서 사용하면 된다.
'iOS (기능)' 카테고리의 다른 글
[SWIFT] Substring is deprecated (0) | 2019.01.09 |
---|---|
[SWIFT] 딜리게이트(Delegate) 패턴 사용하기 (1) | 2019.01.02 |
[SWIFT] UIScrollbar의 Scrollbar(indicator)접근하기 (0) | 2018.12.24 |
[iOS] Reject : Guideline 4.2.6 (0) | 2018.12.13 |
[SWIFT] Static Cell을 사용하는 테이블 뷰의 커스터마이징(뷰 추가하기) (0) | 2018.06.19 |