컨테이너 보기를 프로그래밍 방식으로 추가하는 방법
컨테이너 보기는 인터페이스 편집기를 통해 스토리보드에 쉽게 추가할 수 있습니다.추가할 경우, 컨테이너 뷰는 자리 표시자 뷰, 포함 세그먼트 및 (하위) 뷰 컨트롤러에 대한 것입니다.
그러나 Container View를 프로그래밍 방식으로 추가하는 방법을 찾을 수 없습니다.사실, 나는 심지어 이름이 붙은 수업을 찾을 수 없습니다.UIContainerView
그 정도.
Container View 클래스의 이름은 확실히 좋은 시작입니다.segue를 포함한 완전한 가이드를 해주시면 감사하겠습니다.
View 컨트롤러 프로그래밍 가이드는 알고 있지만 인터페이스 작성기가 Container Viewer에 대해 수행하는 방식과 동일하다고 생각하지 않습니다.예를 들어, 제약 조건이 적절하게 설정되면 (하위) 보기는 컨테이너 보기의 크기 변경에 따라 조정됩니다.
스토리보드 "컨테이너 뷰"는 표준일 뿐입니다.UIView
물건.특별한 "컨테이너 뷰" 유형은 없습니다.실제로 보기 계층을 보면 "컨테이너 보기"가 표준임을 알 수 있습니다.UIView
:
프로그래밍 방식으로 이를 달성하려면 "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)
}
이 후자의 패턴은 서로 다른 하위 뷰 컨트롤러 간에 전환될 때마다 한 하위 뷰가 동일한 위치에 있고 이전 하위 뷰(즉, 배치에 대한 모든 고유 제약 조건이 컨테이너 뷰에 의해 지정됨)를 확인하려는 경우 매우 유용합니다.이러한 제약 조건을 매번 재구축할 필요가 없습니다.).그러나 단순 뷰 제한을 수행하는 경우에는 별도의 컨테이너 뷰가 필요하지 않습니다.
에서 저는 위의예에서, 설정니다합나는다니설합을 설정하고 .translatesAutosizingMaskIntoConstraints
false
스스로 제약 조건을 정의합니다.당신은 분명히 떠날 수 있습니다.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)")
}
}
결과.
언급URL : https://stackoverflow.com/questions/37370801/how-to-add-a-container-view-programmatically
'programing' 카테고리의 다른 글
사용자가 C# + As에서 Active Directory 그룹에 속해 있는지 확인합니다.그물 (0) | 2023.08.01 |
---|---|
각각 고유한 @Controller가 있는 여러 DispatcherServlet을 사용하는 스프링 부팅 (0) | 2023.06.22 |
스프링 부트 상태 비저장 필터가 두 번 호출되는 이유는 무엇입니까? (0) | 2023.06.22 |
DisplayAttribute를 표시하려면 어떻게 해야 합니다.설명 특성 값? (0) | 2023.06.22 |
간격을 분으로 변환 (0) | 2023.06.22 |