【问题标题】:How to put subclassed view controller's view into super class baseviewcontroller's contentview?如何将子类视图控制器的视图放入超类 baseviewcontroller 的内容视图中?
【发布时间】:2019-12-19 15:38:30
【问题描述】:

我创建了一个名为baseviewcontroller 的超类uiviewcontroller 来包含我的大多数应用程序屏幕所需的基本用户界面。它包括一个自定义的navigation 栏和一个“自定义选项卡栏”,我使用视图底部的UIViewprotocols 在xib 中创建。因此,在未来,我希望仅将这个baseviewcontroller 子类化,以包含其所有基本UI 元素。我可以继承这个baseviewcontroller 没问题,但是底部的新uiviewcontroller's ui 元素将被我创建的“标签栏”覆盖。

我尝试在baseviewcontroller 中添加一个名为内容视图的新UIView,设置其与“标签栏”相关的约束,并在随后的视图控制器中尝试将其视图添加到contentview。但它给了我错误(CALayer 需要它自己的层树),基本上说我不应该这样做contentview.addsubview(self.view)。所以我尝试使用约束将新的viewcontroller's 视图与内容视图匹配,但约束失败并且不再显示选项卡栏。关于如何做到这一点的任何想法,可能来自baseviewcontroller

class BaseViewController: UIViewController, SlideMenuDelegate, SwitchTabBarDelegate{

//some other ui,custom nav and controls stuff

private var switchTabBar : SwitchTabBar!
var contentView : UIView!

override func viewDidLoad(){
    super.viewDidLoad()
    self.configureNavBar()
    self.configureScreenEdgeRecognizer()
    self.configureBaseView()
}

private func configureBaseView(){
        //set up contentView for future View to add into
        self.contentView = UIView(frame: CGRect.zero)
        self.view.addSubview(contentView)
        self.contentView.translatesAutoresizingMaskIntoConstraints = false
        self.contentView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
        self.contentView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        self.contentView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor).isActive = true

        //set up switchtabbar for switching between viewcontrollers that inherit from base viewcontroller
        self.switchTabBar = SwitchTabBar(frame: CGRect.zero)
        self.switchTabBar.delegate = self
        self.view.addSubview(switchTabBar)
        self.switchTabBar.translatesAutoresizingMaskIntoConstraints = false
        self.view.addConstraint(NSLayoutConstraint(item: self.contentView!, attribute: .bottom, relatedBy: .equal, toItem: self.switchTabBar!, attribute: .top, multiplier: 1, constant: 0))
        self.switchTabBar.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        self.switchTabBar.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        self.switchTabBar.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        self.switchTabBar.heightAnchor.constraint(equalToConstant: self.view.bounds.size.height/10).isActive = true
    }

// some other ui functions and controls + delegate method
}

class MainPageViewController: BaseViewController{

    override func viewDidLoad(){
        super.viewDidLoad()
        contentView.addsubview(self.view) //gives error
        //or
        self.view.frame = contentView.frame //doesn't work
        //or
        self.view.frame = contentView.bounds //doesn't work
        self.view.topAnchor.constraint(contentView.topAnchor).isActive = true
         /* lead,trail,bottom constraint etc but constraint breaks onruntime and won't show tab-bar anymore */
    }

    //edit: tried new method
    override func viewDidLayoutSubviews(){
         super.viewDidLayoutSubviews()
         // this create half black screen so still doesn't work
         self.view.frame = self.contentView.bounds //think because contentView is constraint to the actual view it doesn't work.
    }

}

请注意,BaseViewController 没有.xib 或存在于storyboard 中,并且完全由代码编写,但随后的viewcontroller 可以并且将在storyboard 上使用网点等设计师可以改变它的外观。

编辑后:从这个实验来看,从我尝试输入viewDidLayoutSubviews 时得到的半黑屏来看,似乎BaseViewController 的视图和inherit-class 的视图是相同的。现在猜猜我将通过在情节提要中添加一个具有清晰颜色的空视图然后围绕它构建来围绕底部标签栏构建设计。

【问题讨论】:

  • 除了在底部的那个栏周围设置视图之外别无他法,你不能创建视图控制器并将其隐藏在它自己的视图中。就像你想躲在自己的口袋里一样

标签: ios swift uiview uiviewcontroller storyboard


【解决方案1】:

好的,我知道了。在尝试了不同的方法后,我发现了一种可以做到这一点但不是很优雅的方法。

我已经从我的BaseViewController 中删除了我的contentView,在我的继承类MainPageViewController 故事板中,我添加了一个视图,将其命名为contentView 并使其自动布局到安全区域,但是我抓住bottomConstraint 并在viewController 中有一个出口。 然后我在运行时将其删除,然后将contentView 的底部连接约束添加到switchTabBar 的顶部,瞧。

class MainViewController: BaseViewController {

    @IBOutlet weak var newContentView: UIView!
    @IBOutlet weak var newContentBottomConstraint: NSLayoutConstraint!

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

    private func setUpView(){
        self.newContentBottomConstraint.isActive = false
        self.view.addConstraint(NSLayoutConstraint(item: self.newContentView!, attribute: .bottom, relatedBy: .equal, toItem: self.switchTabBar!, attribute: .top, multiplier: 1, constant: 0))
    }

}

所以现在我只需要先在未来的viewController 类上添加“contentView”,然后在“contentView”中进行所有设计,就像您使用 contentView 进行scrollView 一样。这个答案不是很优雅,但我猜它可以完成工作。如果其他人有更好的解决方案,请发布,如果不是太麻烦,我可以相应地更改

【讨论】:

    【解决方案2】:

    在子视图控制器中尝试使用边界而不是设置框架,例如:self.view.frame = contentView.bounds

    同时删除行contentView.addsubview(self.view),因为视图已经是视图层次结构的一部分

    所以您的子视图控制器的 didLoad 方法可能如下所示:

    class MainPageViewController: BaseViewController{
    
        override func viewDidLoad(){
            super.viewDidLoad()
            self.view.frame = contentView.bounds //doesn't work
        }
    
    }
    

    希望对你有帮助..!!!

    【讨论】:

    • 它不起作用,我尝试添加调试消息以帮助我理解,但显然,由于我使用 cgRect.zero 启动了内容视图,高度为零,在我按照你的方法设置它之后,视图框架高度也设置为零,然后立即回到原来的高度
    猜你喜欢
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-10
    • 2015-11-16
    相关资源
    最近更新 更多