【Swift】 다른 ViewController의 View를 사용하고 싶다! (ContainerView)

소개



지난번 이런 기사 을 투고했습니다. 부모 View에 자식 View를 추가하거나 지우거나 다른 ViewController의 View를 사용하는 방법입니다.
그러나 이 방법으로 표시하고 싶은 ViewController의 높이를 바꾸고 싶을 때 레이아웃이 잘 작동하지 않습니다. (레이아웃을 하고 있지 않기 때문에,,,,)
아래의 녹색 뷰에 빨간색 뷰 컨트롤러의 빨간색 뷰, 파란색 뷰 컨트롤러의 파란색 뷰를 표시하려고 하면 가운데에 중간 레이블이 표시되지 않습니다. 이것은, 표시하고 싶은 ViewController의 톱과 녹색의 View의 톱이 같은 설정이 되어 있기 때문이군요.


억지로 하는 방법도 있습니다만, 좀 더 능숙한 방법이 있으므로, 이번은 그것을 소개합니다.
(나의 명예를 위해서, 레이아웃을 확실히 붙여 대응한 것은 이하에 실어 둡니다(원래 명예 따위 없다))

이번에는 centerXAnchor 필요하지 않지만.
그럼, 본제에 들어갑시다.

이번에 만드는 것





빨간색과 파란색 부분은 ContainerView입니다. 버튼을 누르면 테이블 뷰에 각각 값을 추가해 나가는 간단한 앱을 생각해 봅시다.

GitHub



구현



Storyboard 만들기



계층 구조는 다음과 같습니다. (자동 레이아웃 등은 GitHub를 참조하십시오)


소스 코드



ContainerView를 전환하고 싶으므로 ContainerA와 ContainerB의 상위 View를 준비하고 ContainerA와 Container를 세그먼트로 전환합니다.

TopViewController
import UIKit

final class TopViewController: UIViewController {

    @IBOutlet private weak var containerView: UIView!
    @IBOutlet private weak var containerA: UIView!
    @IBOutlet private weak var containerB: UIView!
    @IBOutlet private weak var tableView: UITableView!

    private var containers = [UIView]()
    private var texts = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        containers.append(containerA)
        containers.append(containerB)
        containerView.bringSubviewToFront(containerA)

    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        switch segue.identifier {
            case "ASegueID":
                let redVC = segue.destination as! RedViewController
                redVC.delegate = self
            case "BSegueID":
                let blueVC = segue.destination as! BlueViewController
                blueVC.delegate = self
            default:
                fatalError()
        }
    }

    @IBAction private func segmentDidTapped(_ sender: UISegmentedControl) {
        let currentContainerView = containers[sender.selectedSegmentIndex]
        containerView.bringSubviewToFront(currentContainerView)
    }

}

extension TopViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        texts.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
        let text = texts[indexPath.row]
        cell.textLabel?.text = text
        return cell
    }

}

extension TopViewController: ContainerViewDelegate {
    func input(_ text: String) {
        texts.append(text)
        tableView.reloadData()
    }
}

RedViewController
protocol ContainerViewDelegate: AnyObject {
    func input(_ text: String)
}

final class RedViewController: UIViewController {

    weak var delegate: ContainerViewDelegate?

    @IBAction private func inputButtonDidTapped(_ sender: Any) {
        delegate?.input("AAAAA")
    }

}

BlueViewController
final class BlueViewController: UIViewController {

    weak var delegate: ContainerViewDelegate?

    @IBAction private func inputButtonDidTapped(_ sender: Any) {
        delegate?.input("BBBBB")
    }

}

해설



테이블 뷰나 델리게이트 주변의 해설은 생략합니다.
Container를 전환하고 싶기 때문에 그것을 저장하는 배열을 준비합니다.
    private var containers = [UIView]()

방금 준비한 배열에 Container를 격납해, 초기 기동했을 때는 containerView에 containerA를 제일 전에 표시시킵니다. ( bringSubviewToFront )
    override func viewDidLoad() {
        super.viewDidLoad()

        containers.append(containerA)
        containers.append(containerB)
        containerView.bringSubviewToFront(containerA)

    }

그리고, 세그먼트(segment)가 선택되었을 때에 표시하는 container를 배열로부터 가져와 방금전의 ( bringSubviewToFront 를 사용해 맨 앞에 표시시킵니다.
    @IBAction private func segmentDidTapped(_ sender: UISegmentedControl) {
        let currentContainerView = containers[sender.selectedSegmentIndex]
        containerView.bringSubviewToFront(currentContainerView)
    }

그리고는 델리게이트나 프로토콜이나를 사용해 테이블 ​​뷰를 갱신해 주면 완성입니다.
그건 그렇고, 뷰 히에랄 키는 이렇게되어 있습니다.



전하고 싶었던 것



이번에는 ContainerView를 사용하여 ViewController를 전환했지만 addChild를 사용한 것보다 쉽지 않았습니까? addChild는 추가하기 전에 remove 할 필요가 있고 ( addSubView없이 insertSubView를 사용하면 좋지만) 자동 레이아웃을 생각해야했습니다. ContainerView를 사용하면 쉽게 ViewController를 전환 할 수 있다고 말하고 싶었습니다. (코드로 한다면 addChild를 사용하는 것이 좋을 것 같네요)

결론



문서를 읽어 보십시오.
ContainerView

좋은 웹페이지 즐겨찾기