컬렉션뷰 데이터소스 객체는 컬렉션뷰와 관련하여 가장 중요한 객체이며, 필수로 제공해야 한다.
컬렉션뷰의 콘텐츠(데이터)를 관리하고 해당 콘텐츠를 표현하는 데 필요한 뷰를 만든다. 데이터소스 객체를 구현하려면 UICollectionViewDataSource 프로토콜을 준수하는 객체를 만들어야 하며, 데이터소스 객체는 최소한 collectionView(_:numberOfItemsInSection:)과 collectionView(_:cellForItemAt:) 메서드를 구현해야 하며 나머지 메서드는 선택사항이다!
필수 메서드
// collectionView(_:numberOfItemsInSection:) : 지정된 섹션에 표시할 항목의 개수를 묻는 메서드funccollectionView(_collectionView:UICollectionView,numberOfItemsInSectionsection:Int)->Int// collectionView(_:cellForItemAt:) : 컬렉션뷰의 지정된 위치에 표시할 셀을 요청하는 메서드funccollectionView(_collectionView:UICollectionView,cellForItemAtindexPath:IndexPath)->UICollectionViewCell
주요 선택 메서드
// numberOfSections(in:) : 컬렉션뷰의 섹션의 개수를 묻는 메서드 > 이 메서드를 구현하지 않으면 섹션 개수 기본 값은 1optionalfuncnumberOfSections(incollectionView:UICollectionView)->Int// collectionView(_:canMoveItemAt:) : 지정된 위치의 항목을 컬렉션뷰의 다른 위치로 이동할 수 있는지를 묻는 메서드optionalfunccollectionView(_collectionView:UICollectionView,canMoveItemAtindexPath:IndexPath)->Bool// collectionView(_:moveItemAt:to:) : 지정된 위치의 항목을 다른 위치로 이동하도록 지시하는 메서드optionalfunccollectionView(_collectionView:UICollectionView,moveItemAtsourceIndexPath:IndexPath,todestinationIndexPath:IndexPath)
델리게이트
컬렉션뷰 델리게이트 프로토콜은 컬렉션뷰에서 셀의 선택 및 강조표시를 관리하고 해당 셀에 대한 작업을 수행할 수 있는 메서드를 정의하며 이 프로토콜의 메서드는 모두 선택사항이다.
주요 메서드
// collectionView(_:shouldSelectItemAt:) : 지정된 셀이 사용자에 의해 선택될 수 있는지 묻는 메서드// 선택이 가능한 경우 true로 응답하며 아닌 경우는 false로 응답optionalfunccollectionView(_collectionView:UICollectionView,shouldSelectItemAtindexPath:IndexPath)->Bool// collectionView(_:didSelectItemAt:) : 지정된 셀이 선택되었음을 알리는 메서드optionalfunccollectionView(_collectionView:UICollectionView,didSelectItemAtindexPath:IndexPath)// collectionView(_:shouldDeselectItemAt:) : 지정된 셀의 선택이 해제될 수 있는지 묻는 메서드 > 선택 해제가 가능한 경우 true로 응답하며, 그렇지 않다면 falseoptionalfunccollectionView(_collectionView:UICollectionView,shouldDeselectItemAtindexPath:IndexPath)->Bool// collectionView(_:didDeselectItemAt:) : 지정된 셀의 선택이 해제되었음을 알리는 메서드optionalfunccollectionView(_collectionView:UICollectionView,didDeselectItemAtindexPath:IndexPath)// collectionView(_:shouldHighlightItemAt:) : 지정된 셀이 강조될 수 있는지 묻는 메서드 > 강조해야 하는 경우 true로 응답하며, 그렇지 않다면 false optionalfunccollectionView(_collectionView:UICollectionView,shouldHighlightItemAtindexPath:IndexPath)->Bool// collectionView(_:didHighlightItemAt:) : 지정된 셀이 강조되었을 때 알려주는 메서드optionalfunccollectionView(_collectionView:UICollectionView,didHighlightItemAtindexPath:IndexPath)// collectionView(_:didUnhighlightItemAt:) : 지정된 셀이 강조가 해제될 때 알려주는 메서드optionalfunccollectionView(_collectionView:UICollectionView,didUnhighlightItemAtindexPath:IndexPath
계층구조로 구성된 content를 순차적으로 보여주는 container view controller
stack 구조로 구현 > navigation stack
계층 구조 탐색으로 앱 content를 보여주기 적절
한번에 한 child view controller의 content만 보여짐
이는 트리 구조처럼 상위 카테고리에서 점차 하위 카테고리로 넓어져 가는 구조를 표현하며 상위 카테고리로 돌아가기 위해서는 가장 최근에 보여진 뷰컨트롤부터 역순으로 거쳐 가야한다. 따라서 스택구조가 이를 구현하기에 적절하다. 이러한 네비게이션 뷰 컨트롤러는 pop/push메소드를 사용하여 보여지는 child view controller를 변경이 가능하다.
Navigation Bar > UINavigationBar
화면 상단에 있는 항상 보여지는 바
root view 외의 모든 view 에서 back버튼이 있어 user가 계층구조에서 다시 뒤로 올라갈 수 있게끔 함
현재 stack의 top level에 있는 view controller가 변하면 그에 맞게 navigation controller의 navigation bar도 변함
navigation bar button item: left, middle, right
View controller - title property 설정시 navigation bar의 가운데에 표시됨
Stack에 다음 View Controller를 쌓으며 디스플레이하는 것이 Push, 이전의 View Controller로 되돌아가는 것이 Pop 액션이다. Pop 액션에는 최초에 디스플레이됐던 View Controller로 돌아가는 Pop to Root 액션이 포함되어 있다.
Optional Tool Bar
Tool bar는 현재 위치한 content에서 할 수 있는 조작을 보여주는 bar
tab bar는 content 간 전환에 사용됨
tool bar 는 현재 content 내에서의 가능한 동작을 보여주는 용도
Tool Bar 보여주기
isToolBarHidden property == false 이면 tool bar displayed
Interface Builder 에서 ✅ Show Toolbar
Tool Bar item 추가하기
toolbar가 보여질 때, 현재 활성화된(active) view controller의 toolBarItems property를 보여줌
view controller 의 toolBarItems (UIBarButtonItem type) 에 객체 넣어주면 tool bar에 item이 보임
View Controller
뷰를 제어하는 컨트롤러 객체
view 프로퍼티를 가짐으로써 프로퍼티로 가지고 있는 뷰와 서브뷰의 레이아웃이나 모양, 컨텐츠를 변경
뷰 내의 컨트롤을 사용자가 조작할때 호출되는 액션을 처리
뷰의 라이프 사이클을 관리
모든 뷰가 뷰컨트롤러를 가질 필요는 없으며 앱의 전체화면 영역을 차지하는 뷰마다 1개씩 있으면 됨
뷰 컨트롤러는 단일 루트 뷰를 관리하며 자체에는 여러 개의 하위 뷰가 포함될 수 있다. 해당 뷰 계층과의 사용자 상호 작용은 필요에 따라 앱의 다른 객체와 조정되는 뷰 컨트롤러에서 처리한다.
모든 앱에는 컨텐츠가 기본 창을 채우는 하나 이상의 뷰 컨트롤러가 있다
앱에 한 번에 화면에 표시 할 수있는 것보다 더 많은 콘텐츠가있는 경우 여러 뷰 컨트롤러를 사용하여 해당 콘텐츠의 다른 부분을 관리
컨터에너는 컨텐츠를 관리하는 것이 아니라 루트뷰만 관리하며 컨테이너 디자인에 따라 크기 조정
UINavigationController, UITabbarController, UIPageViewController 등
ViewController는 Responder 객체다. 직접 이벤트를 받아 처리하는것이 가능하나 일반적으로 지양!
뷰가 그 자신의 터치 이벤트를 연관된 객체(보통 뷰컨트롤러)에 action 메서드나 delegate로 전달
The Root View Controller
UIWindow는 그 자체로는 유저에게 보여지는 콘텐츠를 가지지 못한다
Window는 정확히 하나의 RootViewController를 가지고 이를통해 컨텐츠를 표현
Container View Controller
Presented View Controller
내 생각 정리
추가해야하거나 잘못된 점은 댓글로 알려주시면 감사하겠습니다 :)
궁극적으로 네이게이션 컨트롤러는 스택같은 계층구조임을 떠올리면 된다. 예로 들어 생각해보면 아래와 같다.
설정 -> 내이름 터치 > 이름, 전화번호, 이메일 > 이름
이런식으로 하나의 갈래에서 정보를 파고파고 들어가는 형태이다. 이때 각 뷰컨트롤러의 데이터는 우리가 push해서 들어갈때마다 이전 정보를 저장해주고 있으며 그렇기 때문에 우리가 현재 화면에서 이전화면으로 돌아간다하더라도(pop) pop을 통해 타고타고 돌아가는것이 가능하다. 맨 첫화면으로 바로 돌아갈 수도 있는데 이를 잘 활용하기 위해서는 반드시 root view controller를 지정해주는 것이 필요하다!
반면 뷰 컨트롤러는 각 뷰컨트롤러마다의 데이터를 다른 뷰 컨트롤러가 저장을 해놓고 있지 않다. 우리가 만약에 첫번째 뷰 컨트롤러에서 두번째 뷰 컨트롤러, 세번째 뷰 컨트롤러로 타고타고 넘어갔다고 하자. 현재 유저의 화면이 세번째 뷰 컨트롤러에 있다면 그 뷰컨트롤러에서는 첫번째 뷰 컨트롤러의 데이터를 가지고 있지 않다. 따라서 세번째에서 첫번쨰로 넘어가려고 한다면 그 방법이 존재하지 않는다. 그 이유는 첫번째 뷰 컨트롤러에 대한 정보를 가지고 있지 않기 때문이다.
뷰 컨트롤러의 present는 단순히 덮어씌우기 기능이라고 생각하면 쉽다. 첫번째 뷰 컨트롤러의 정보를 두번째 뷰 컨트롤러에 덮어씌운다. 그렇기 때문에 바로 전 뷰 컨트롤러의 정보에 대해서만 간직하고 있다. 우리가 dismiss를 두번한다고 해서 세번째에서 첫번째 뷰 컨트롤러로 접근할수가 없다.
개발을 할때 정보의 흐름이 하나로 주욱 이어지는 화면을 구현해야한다면 네비게이션 컨트롤러를 사용하고, 각각의 독립적인 뷰를 보여줘야한다면 뷰 컨트롤러를 사용하는게 옳다고 생각한다. 그렇지만 이 둘을 또 각각 다른 단독적인 애들이라고 생각하기 보다는 기본적으로 우리는 뷰 컨트롤러를 사용하고 그 안에서 정보의 흐름이 이어지는 구성이 필요하다면 네비게이션 컨트롤러를 선택적으로 사용하며 그 흐름을 뷰 컨트롤러로 push, pop하는 것이라고 생각하는게 옳은 것 같다.
애플리케이션 내에서 특정 아이템을 복사하거나 외부 SNS로 공유하는 내보내기 서비스는 사용자가 아이템을 다양한 방식으로 활용하도록 도와준다. iOS 6 이상부터 사용 가능한 UIActivityViewController 클래스는 아래 이미지와 같은 내보내기 서비스를 손쉽게 사용할 수 있도록 해준다.
Acitivity Item
UIActivityViewController 클래스를 이용해 아래 아이템을 공유할 수 있다.
문자열(String)
URL 링크(String)
이미지(UIImage)
UIActivityItemSource 프로토콜을 따르는 커스텀 타입의 인스턴스
Activity Type
UIActivityViewController 클래스가 기본적으로 제공하는 내보내기 서비스의 UIActivity에는 아래와 같은 종류가 있다.
// 읽기 목록에 추가staticletaddToReadingList:UIActivityType// 에어드롭으로 공유하기staticletairDrop:UIActivityType// 연락처에 지정staticletassignToContact:UIActivityType// Paste Board에 복사staticletcopyToPasteboard:UIActivityType// 메일 보내기staticletmail:UIActivityType// 메시지 보내기staticletmessage:UIActivityType// iBooks에서 열기staticletopenInIBooks:UIActivityType// 페이스북에 공유하기staticletpostToFacebook:UIActivityType// Flickr에 공유하기staticletpostToFlickr:UIActivityType// Tencent Weibo에 공유하기staticletpostToTencentWeibo:UIActivityType// 트위터에 공유하기staticletpostToTwitter:UIActivityType// Vimeo에 공유하기staticletpostToVimeo:UIActivityType// SinaWeibo에 공유하기staticletpostToWeibo:UIActivityType// 프린트staticletprint:UIActivityType// 카메라 롤에 저장하기staticletsaveToCameraRoll:UIActivityType// PDF 생성(iOS 11 부터 사용가능)staticletmarkupAsPDF:UIActivityType
메서드 및 프로퍼티
UIActivityViewController의 메서드와 프로퍼티에는 어떤 것이 있으며 어떤 역할을 하는지 알아보자
// 초기화 메서드로, UIActivityViewController 객체를 반환합니다.init(activityItems:[Any],applicationActivities:[UIActivity]?)// activityItems: [Any] 공유하려는 아이템으로 UIActivityItemSource 프로토콜을 준수하는 객체를 배열 형태로 넣어줄 수 있습니다.// applicationActivities: [UIActivity]? 애플리케이션이 지원하는 커스텀 서비스를 나타내는 UIActivity 객체의 배열로, nil 값이 될 수 있습니다.// 컨트롤러를 닫은 후 실행할 완료 핸들러입니다.varcompletionWithItemsHandler:UIActivityViewControllerCompletionWithItemsHandler?// UIActivityType 중 사용하지 않을 서비스를 지정합니다.varexcludedActivityTypes:[UIActivityType]?
샘플 코드
// 1. UIActivityViewController 초기화, 공유 아이템 지정letimageToShare:UIImage=UIImage(named:"image.png")leturlToShare:String="http://www.edwith.org/boostcourse-ios"lettextToShare:String="안녕하세요, 부스트 코스입니다."letactivityViewController=UIActivityViewController(activityItems:[imageToShare,urlToShare,textToShare],applicationActivities:nil)// 2. 기본으로 제공되는 서비스 중 사용하지 않을 UIActivityType 제거(선택 사항)activityViewController.excludedActivityTypes=[UIActivityType.addToReadingList,UIActivityType.assignToContact]// 3. 컨트롤러를 닫은 후 실행할 완료 핸들러 지정activityViewController.completionWithItemsHandler={(activity,success,items,error)inifsuccess{// 성공했을 때 작업}else{// 실패했을 때 작업}}// 4. 컨트롤러 나타내기(iPad에서는 팝 오버로, iPhone과 iPod에서는 모달로 나타냅니다.)self.present(activityViewController,animated:true,completion:nil)
UICollectionViewFlowLayout 클래스를 사용하면 컬렉션뷰의 셀을 원하는 형태로 정렬할 수 있다. 플로우 레이아웃은 레이아웃 객체가 셀을 선형 경로에 배치하고 최대한 이 행을 따라 많은 셀을 채우는것을 의미한다. 현재 행에서 레이아웃 객체의 공간이 부족하면 새로운 행을 생성하고 거기에서 레이아웃 프로세스를 계속 진행한다.
overridefuncviewDidLoad(){super.viewDidLoad()// Do any additional setup after loading the view.letflowLayout:UICollectionViewFlowLayout// 이 타입의flowLayout=UICollectionViewFlowLayout()// 인스턴스 생성// section의 inset을 없애고flowLayout.sectionInset=UIEdgeInsets.zero// 아이템간의 거리flowLayout.minimumInteritemSpacing=10// 줄 간의 거리 (단위는 포인트)flowLayout.minimumLineSpacing=10lethalfWidth:CGFloat=UIScreen.main.bounds.width/2.0// 오토레이아웃에 따라 사이즈는 가변적이기 때문에 정도값을 알려주는 것flowLayout.estimatedItemSize=CGSize(width:halfWidth-30,height:90)self.collectionView.collectionViewLayout=flowLayout}