Jonno
Jonno

Reputation: 65

Creating UIViewController programmatically does not show subviews or recognise gestures

I am trying to create a View Controller entirely programmatically to use it as a slide-out menu to be accessed from any scene in my app. There are many other VCs in the app that use storyboard (one day I'll be able to remove storyboard altogether I hope). My code is like this:

import UIKit

class MenuViewController: UIViewController {

var stkMenu: UIStackView {
    let s = UIStackView(frame: view.frame)
    s.axis = .vertical
    s.distribution = .fillEqually
    s.alignment = .fill
    s.translatesAutoresizingMaskIntoConstraints = false
    return s
}

var butSettings: UIButton = {
    let b = UIButton()
    b.backgroundColor = UIColor.clear
    b.setTitle("SETTINGS", for: .normal)
    b.showsTouchWhenHighlighted = true
    b.titleLabel?.font = UIFont(name: "Roboto-Bold", size: 20)
    b.setTitleColor(UIColor.netScoreGreen(), for: .normal)
    b.translatesAutoresizingMaskIntoConstraints = false
    return b
}()

var butAbout: UIButton = {
    let b = UIButton()
    b.backgroundColor = UIColor.clear
    b.setTitle("ABOUT", for: .normal)
    b.showsTouchWhenHighlighted = true
    b.titleLabel?.font = UIFont(name: "Roboto-Bold", size: 20)
    b.setTitleColor(UIColor.netScoreGreen(), for: .normal)
    b.translatesAutoresizingMaskIntoConstraints = false
    return b
}()

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.black
    stkMenu.addArrangedSubview(butSettings)
    stkMenu.addArrangedSubview(butAbout)
    view.addSubview(stkMenu)
    view.translatesAutoresizingMaskIntoConstraints = false
    let swipe = UISwipeGestureRecognizer(target: self.view, action: #selector(dismissVC))
    self.view.addGestureRecognizer(swipe)
    swipe.direction = .right
    swipe.isEnabled = true
//        NSLayoutConstraint.activate([
//            stkMenu.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
//            stkMenu.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -50),
//            stkMenu.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
//            stkMenu.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
//            ])
    view.layoutIfNeeded()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

@objc func dismissVC() {
    self.dismiss(animated: true, completion: nil)
}
}

Pretty much everything I try with this doesn't work. When I present the View Controller, I do not see the stack view with the two buttons on it, the swipe gesture does not seem to be recognised at all, so I cannot dismiss the VC, and if I uncomment the constraint lines, I get BAD ACCESS when it executes them.

I have used constraints, stack views, gestures in other parts of the app (admittedly there's always been a storyboard behind them), but this is my first venture into doing away with them and it has me stumped. I'd like to be able to see and use the buttons (I'll add targets for them once I can see them), dismiss the VC using a swipe, and make the stack view take the entire view, none of which seems to be working. I'm probably missing something simple but can't see it for the life of me.

Upvotes: 0

Views: 67

Answers (2)

Shehata Gamal
Shehata Gamal

Reputation: 100503

You declared the UIStackView as a computed property it has to be a lazy var

lazy var stkMenu: UIStackView =  {
    let s = UIStackView(frame: CGRect.zero)
    s.axis = .vertical
    s.distribution = .fillEqually
    s.alignment = .fill
    s.translatesAutoresizingMaskIntoConstraints = false
    return s
}()

also don't forget to un comment the constraints and comment this line

view.translatesAutoresizingMaskIntoConstraints = false

as by it you destroy the layout of the view

Upvotes: 2

DonMag
DonMag

Reputation: 77462

Looks like you simply mis-typed the declaration, plus you don't need to set the frame of the stack view...

Your code:

var stkMenu: UIStackView {
    let s = UIStackView(frame: view.frame)
    s.axis = .vertical
    s.distribution = .fillEqually
    s.alignment = .fill
    s.translatesAutoresizingMaskIntoConstraints = false
    return s
}

code that works (by un-commenting the constraints):

var stkMenu: UIStackView = {
    let s = UIStackView() //frame: view.frame)
    s.axis = .vertical
    s.distribution = .fillEqually
    s.alignment = .fill
    s.translatesAutoresizingMaskIntoConstraints = false
    return s
}()

Upvotes: 1

Related Questions