- Designing a Custom Container View Controller
- Configuring a Container in Interface Builder
- Implementing a Custom Container View Controller
- Suggestions for Building a Container View Controller
- Delegating Control to a Child View Controller
예시)
Navigation Controller 는 navigation stack을 통해 navigation 을 지원한다.
Split ViewController는 2개의 ViewController 를 Master - Detail 배치로 보여준다.
이 배치에서 Master VC 의 content 는 다른 Detail VC의 정보를 결정한다.
두 VC 가 보여지는 것은 현재 환경에 따라 달라진다.
Size class
레귤러-가로 (regular-horizontal): Master - Detail 두 VC를 모두 보여주거나 Master는 필요할 때만 보여줄 수 있다
컴팩트 (compact): 한 번에 하나의 VC만 보여줄 수 있다
Child VC 의 View를 관리하기 전에 Parent - Child 관계를 설정해야 UIKit에서 Parent VC가 Child VC의 view의 크기와 위치를 관리하고 있음을 알 수 있다.
이러한 관계는 (위의 경우 처럼) 스토리보드로 구현할 수도 있고 코드로 구현할 수 있다.
코드로 구현하는 경우 Child VC 를 명시적으로 추가하고 제거해야 한다.
📌보충설명: (ChildVC 를 지역변수로 선언하는 경우) Child VC를 초기화한 메서드가 끝나면 ChildVC 는 레퍼런스 카운트가 0이 되서 deinit 된다. 하지만 ChildVC 의 view 는 addSubView 에 의해 레퍼런스 카운트가 늘어난 상태이기 때문에 Child VC가 종료되도 View 는 deinit 되지 않는다.
override var shouldAutomaticallyForwardAppearanceMethods: Bool {
false
}
false 인 경우 자식 VC의 appearance methods 를 호출하는 책임을 프로그래머가 가지게 된다
(apperance methods: viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear)
직접 호출 대신 아래와 같이 호출 가능
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
childVC.beginAppearanceTransition(true, animated: animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
childVC.endAppearanceTransition()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
childVC.beginAppearanceTransition(false, animated: animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
childVC.endAppearanceTransition()
}
Container VC 를 구현할 때 참고할 것들
(더 단순화된 조건에서 레이아웃 제약조건, 애니메이션 전환 테스트)
: Child VC 에게 제어 권한 위임하기
class ContainerVC: UINavigationController {
override var childForStatusBarStyle: UIViewController? {
return self.topViewController
}
}
class ChildVC: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
: StatusBar 는 ContainerVC 에서 관리하기 때문에 ChildVC 에서 Status Bar 를 설정하게 하고 싶은 경우 ContainerVC 에서 childForStatusBarStyle 을 override 해서 topViewController 를 반환해야 ChildVC에서 preferredStatusBarStyle 이 호출됨
ContainerVC 에서 ChildVC 의 preferredContentSize 를 이용하여 ChildVC 의 view 의 크기를 조정할 수 있다.
class LibraryContainerViewController: UIViewController { // Container VC
private let library = [
Book(title: "Alice's Adventures in Wonderland", author: "Lewis Caroll", firstLine: "Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, ‘and what is the use of a book,’ thought Alice ‘without pictures or conversations?’"),
Book(title: "Emma", author: "Jane Austen", firstLine: "Emma Woodhouse, handsome, clever, and rich, with a comfortable home and happy disposition, seemed to unite some of the best blessings of existence; and had lived nearly twenty-one years in the world with very little to distress or vex her."),
Book(title: "Great Expectations", author: "Charles Dickens", firstLine: "My father's family name being Pirrip, and my Christian name Philip, my infant tongue could make of both names nothing longer or more explicit than Pip."),
Book(title: "Metamorphosis", author: "Franz Kafka", firstLine: "One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin."),
Book(title: "Peter Pan", author: "James M. Barrie", firstLine: "All children, except one, grow up.")
]
@IBOutlet private var messageHeightConstraint: NSLayoutConstraint?
private var previewController: MessageViewController?
private var listTableViewController: BookListTableViewController?
override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
super.preferredContentSizeDidChange(forChildContentContainer: container)
if (container as? MessageViewController) != nil {
messageHeightConstraint?.constant = container.preferredContentSize.height
}
}
}
class MessageViewController: UIViewController { // Child ViewController
@IBOutlet private var messageLabel: UILabel!
var message: String? {
didSet {
updateMessage()
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateMessage()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
calculatePreferredSize()
}
private func calculatePreferredSize() {
preferredContentSize = messageLabel.intrinsicContentSize
}
private func updateMessage() {
messageLabel?.text = message
}
}
ContainerVC → ChildVC 로 text 전달
ChildVC
ContainerVC
: 호출된 preferredContentSizeDidChange 를 통해 ChildVC의 preferredContentSize 받고 ChildVC.view 의 height Constraint 를 업데이트
: 장애인과 비장애인이든 상관없이 모든 사람들에게 최대한 동일한 UX를 제공하는 것
: 간단하지만 가장 핵심적인 메서드
backButton.accessibilityLabel = "뒤로가기"
UIAccessibility.post(
notification: UIAccessibility.Notification.screenChanged,
argument: view
)
: Focus 순서 제어
cell.accessibilityElements = [cell.nameLabel, cell.ageLabel, cell.homeLabel]
: 보이스오버 일 때, 아닐 때 분기처리해서 로직을 나눌 수 있음
HIG
https://developer.apple.com/design/human-interface-guidelines/accessibility/overview/introduction/