programing

컨테이너 보기를 프로그래밍 방식으로 추가하는 방법

firstcheck 2023. 6. 22. 23:57
반응형

컨테이너 보기를 프로그래밍 방식으로 추가하는 방법

컨테이너 보기는 인터페이스 편집기를 통해 스토리보드에 쉽게 추가할 수 있습니다.추가할 경우, 컨테이너 뷰는 자리 표시자 뷰, 포함 세그먼트 및 (하위) 뷰 컨트롤러에 대한 것입니다.

그러나 Container View를 프로그래밍 방식으로 추가하는 방법을 찾을 수 없습니다.사실, 나는 심지어 이름이 붙은 수업을 찾을 수 없습니다.UIContainerView그 정도.

Container View 클래스의 이름은 확실히 좋은 시작입니다.segue를 포함한 완전한 가이드를 해주시면 감사하겠습니다.

View 컨트롤러 프로그래밍 가이드는 알고 있지만 인터페이스 작성기가 Container Viewer에 대해 수행하는 방식과 동일하다고 생각하지 않습니다.예를 들어, 제약 조건이 적절하게 설정되면 (하위) 보기는 컨테이너 보기의 크기 변경에 따라 조정됩니다.

스토리보드 "컨테이너 뷰"는 표준일 뿐입니다.UIView물건.특별한 "컨테이너 뷰" 유형은 없습니다.실제로 보기 계층을 보면 "컨테이너 보기"가 표준임을 알 수 있습니다.UIView:

container view

프로그래밍 방식으로 이를 달성하려면 "view controller containment"를 사용합니다.

  • 호출하여 하위 보기 컨트롤러 인스턴스화instantiateViewController(withIdentifier:)스토리보드 객체에 있습니다.
  • 불러addChild상위 보기 컨트롤러에 있습니다.
  • 보기 컨트롤러 추가view사용자의 보기 계층으로addSubview(및 설정)frame또는 해당되는 제약 조건).
  • 콜 더didMove(toParent:)참조를 상위 뷰 컨트롤러로 전달하는 하위 뷰 컨트롤러의 메서드입니다.

View 컨트롤러 프로그래밍 가이드의 컨테이너컨트롤러 구현UIView 컨트롤러 클래스 참조의 "컨테이너 뷰 컨트롤러 구현" 섹션을 참조하십시오.


예를 들어 Swift 4.2에서는 다음과 같이 보일 수 있습니다.

override func viewDidLoad() {
    super.viewDidLoad()

    let controller = storyboard!.instantiateViewController(withIdentifier: "Second")
    addChild(controller)
    controller.view.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(controller.view)

    NSLayoutConstraint.activate([
        controller.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
        controller.view.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
        controller.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 10),
        controller.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10)
    ])

    controller.didMove(toParent: self)
}

위에서는 실제로 "컨테이너 보기"를 계층에 추가하지 않습니다.이 작업을 수행하려면 다음과 같은 작업을 수행합니다.

override func viewDidLoad() {
    super.viewDidLoad()

    // add container

    let containerView = UIView()
    containerView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(containerView)
    NSLayoutConstraint.activate([
        containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
        containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
        containerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 10),
        containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10),
    ])

    // add child view controller view to container

    let controller = storyboard!.instantiateViewController(withIdentifier: "Second")
    addChild(controller)
    controller.view.translatesAutoresizingMaskIntoConstraints = false
    containerView.addSubview(controller.view)

    NSLayoutConstraint.activate([
        controller.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
        controller.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
        controller.view.topAnchor.constraint(equalTo: containerView.topAnchor),
        controller.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
    ])

    controller.didMove(toParent: self)
}

이 후자의 패턴은 서로 다른 하위 뷰 컨트롤러 간에 전환될 때마다 한 하위 뷰가 동일한 위치에 있고 이전 하위 뷰(즉, 배치에 대한 모든 고유 제약 조건이 컨테이너 뷰에 의해 지정됨)를 확인하려는 경우 매우 유용합니다.이러한 제약 조건을 매번 재구축할 필요가 없습니다.).그러나 단순 뷰 제한을 수행하는 경우에는 별도의 컨테이너 뷰가 필요하지 않습니다.


에서 저는 위의예에서, 설정니다합나는다니설합을 설정하고 .translatesAutosizingMaskIntoConstraintsfalse스스로 제약 조건을 정의합니다.당신은 분명히 떠날 수 있습니다.translatesAutosizingMaskIntoConstraints~하듯이true둘 다 설정합니다.frame원하는 경우 추가할 뷰의 경우 를 참조하십시오.


Swift 3 및 Swift 2 버전은 이 답변의 이전 개정판을 참조하십시오.

@Rob의 Swift 3에서의 대답:

    // add container

    let containerView = UIView()
    containerView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(containerView)
    NSLayoutConstraint.activate([
        containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
        containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
        containerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 10),
        containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10),
        ])

    // add child view controller view to container

    let controller = storyboard!.instantiateViewController(withIdentifier: "Second")
    addChildViewController(controller)
    controller.view.translatesAutoresizingMaskIntoConstraints = false
    containerView.addSubview(controller.view)

    NSLayoutConstraint.activate([
        controller.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
        controller.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
        controller.view.topAnchor.constraint(equalTo: containerView.topAnchor),
        controller.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
        ])

    controller.didMove(toParentViewController: self)

여기 swift 5의 제 코드가 있습니다.

class ViewEmbedder {

class func embed(
    parent:UIViewController,
    container:UIView,
    child:UIViewController,
    previous:UIViewController?){

    if let previous = previous {
        removeFromParent(vc: previous)
    }
    child.willMove(toParent: parent)
    parent.addChild(child)
    container.addSubview(child.view)
    child.didMove(toParent: parent)
    let w = container.frame.size.width;
    let h = container.frame.size.height;
    child.view.frame = CGRect(x: 0, y: 0, width: w, height: h)
}

class func removeFromParent(vc:UIViewController){
    vc.willMove(toParent: nil)
    vc.view.removeFromSuperview()
    vc.removeFromParent()
}

class func embed(withIdentifier id:String, parent:UIViewController, container:UIView, completion:((UIViewController)->Void)? = nil){
    let vc = parent.storyboard!.instantiateViewController(withIdentifier: id)
    embed(
        parent: parent,
        container: container,
        child: vc,
        previous: parent.children.first
    )
    completion?(vc)
}

}

사용.

@IBOutlet weak var container:UIView!

ViewEmbedder.embed(
    withIdentifier: "MyVC", // Storyboard ID
    parent: self,
    container: self.container){ vc in
    // do things when embed complete
}

다른 임베디드 함수는 비스토리보드 뷰 컨트롤러와 함께 사용합니다.

세부 사항

  • Xcode 10.2(10E125), Swift 5

해결책

import UIKit

class WeakObject {
    weak var object: AnyObject?
    init(object: AnyObject) { self.object = object}
}

class EmbedController {

    private weak var rootViewController: UIViewController?
    private var controllers = [WeakObject]()
    init (rootViewController: UIViewController) { self.rootViewController = rootViewController }

    func append(viewController: UIViewController) {
        guard let rootViewController = rootViewController else { return }
        controllers.append(WeakObject(object: viewController))
        rootViewController.addChild(viewController)
        rootViewController.view.addSubview(viewController.view)
    }

    deinit {
        if rootViewController == nil || controllers.isEmpty { return }
        for controller in controllers {
            if let controller = controller.object {
                controller.view.removeFromSuperview()
                controller.removeFromParent()
            }
        }
        controllers.removeAll()
    }
}

사용.

class SampleViewController: UIViewController {
    private var embedController: EmbedController?

    override func viewDidLoad() {
        super.viewDidLoad()
        embedController = EmbedController(rootViewController: self)

        let newViewController = ViewControllerWithButton()
        newViewController.view.frame = CGRect(origin: CGPoint(x: 50, y: 150), size: CGSize(width: 200, height: 80))
        newViewController.view.backgroundColor = .lightGray
        embedController?.append(viewController: newViewController)
    }
}

전체샘플

뷰 컨트롤러

import UIKit

class ViewController: UIViewController {

    private var embedController: EmbedController?
    private var button: UIButton?
    private let addEmbedButtonTitle = "Add embed"

    override func viewDidLoad() {
        super.viewDidLoad()

        button = UIButton(frame: CGRect(x: 50, y: 50, width: 150, height: 20))
        button?.setTitle(addEmbedButtonTitle, for: .normal)
        button?.setTitleColor(.black, for: .normal)
        button?.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        view.addSubview(button!)

        print("viewDidLoad")
        printChildViewControllesInfo()
    }

    func addChildViewControllers() {

        var newViewController = ViewControllerWithButton()
        newViewController.view.frame = CGRect(origin: CGPoint(x: 50, y: 150), size: CGSize(width: 200, height: 80))
        newViewController.view.backgroundColor = .lightGray
        embedController?.append(viewController: newViewController)

        newViewController = ViewControllerWithButton()
        newViewController.view.frame = CGRect(origin: CGPoint(x: 50, y: 250), size: CGSize(width: 200, height: 80))
        newViewController.view.backgroundColor = .blue
        embedController?.append(viewController: newViewController)

        print("\nChildViewControllers added")
        printChildViewControllesInfo()
    }

    @objc func buttonTapped() {

        if embedController == nil {
            embedController = EmbedController(rootViewController: self)
            button?.setTitle("Remove embed", for: .normal)
            addChildViewControllers()
        } else {
            embedController = nil
            print("\nChildViewControllers removed")
            printChildViewControllesInfo()
            button?.setTitle(addEmbedButtonTitle, for: .normal)
        }
    }

    func printChildViewControllesInfo() {
        print("view.subviews.count: \(view.subviews.count)")
        print("childViewControllers.count: \(childViewControllers.count)")
    }
}

버튼이 있는 컨트롤러 보기

import UIKit

class ViewControllerWithButton:UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    private func addButon() {
        let buttonWidth: CGFloat = 150
        let buttonHeight: CGFloat = 20
        let frame = CGRect(x: (view.frame.width-buttonWidth)/2, y: (view.frame.height-buttonHeight)/2, width: buttonWidth, height: buttonHeight)
        let button = UIButton(frame: frame)
        button.setTitle("Button", for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        view.addSubview(button)
    }

    override func viewWillLayoutSubviews() {
        addButon()
    }

    @objc func buttonTapped() {
        print("Button tapped in \(self)")
    }
}

결과.

enter image description here enter image description here enter image description here

언급URL : https://stackoverflow.com/questions/37370801/how-to-add-a-container-view-programmatically

반응형