0

I created a DropDownMenu class, but I need to know when the value changed in the ViewController. Like a UIScrollView didScroll, but for the value change in my class.

func scrollViewDidScroll(_ scrollView: UIScrollView)

I need something like that, but for the class!

Here is the class...

class DropDownMenu: UIStackView {
    
    var options: [String]! = [] // Labels for all of the options
    var titleButton: UIButton! = UIButton() // The Main Title Button
    var target: UIViewController! // The target to get the main view. Maybe remove and automatically do it later
    var textColor: UIColor! = UIColor.black // The Color of the text of the options
    var bgColor: UIColor! = UIColor.clear
    var borderWidth: CGFloat! = 0.0
    var borderColor: CGColor! = UIColor.black.cgColor
    var uiBorderColor: UIColor? = nil
    var cornerRadius: CGFloat! = 0.0
    var font: UIFont! = UIFont.systemFont(ofSize: 18)
    var images: [UIImage]? = nil
    var imageInsets: [UIEdgeInsets]? = nil
    var imageInset: UIEdgeInsets? = nil
    
    var value: String! {
        get {
            return currentSelected
        }
        set {
            currentSelected = newValue
        }
    }
    
    private var currentSelected: String! = ""
    
    init(options: [String]) {
        self.options = options
        
        super.init(frame: CGRect.zero)
        
        self.translatesAutoresizingMaskIntoConstraints = false
        self.axis = .vertical
    }
    
    init(titleButton: UIButton) {
        self.titleButton = titleButton
        
        super.init(frame: CGRect.zero)
        
        self.translatesAutoresizingMaskIntoConstraints = false
        self.axis = .vertical
    }
    
    func createDropDownMenu() {
        currentSelected = titleButton.titleLabel?.text
        let mainFrame = titleButton.frame
        print("Frame: \(mainFrame)")
        print("StackView frame: \(self.frame), axis: \(self.axis)")
        
        if uiBorderColor != nil {
            borderColor = uiBorderColor!.cgColor
        }
        
        self.widthAnchor.constraint(equalToConstant: mainFrame.width).isActive = true
        self.leftAnchor.constraint(equalTo: titleButton.leftAnchor).isActive = true
        self.topAnchor.constraint(equalTo: titleButton.bottomAnchor, constant: self.spacing).isActive = true
        
        var y: CGFloat = 0
        var place = 0
        
        for title in self.options {
            let button = UIButton(frame: CGRect(x: 0, y: y, width: mainFrame.width, height: mainFrame.height))
            button.setTitle(title, for: .normal)
            button.setTitleColor(textColor, for: .normal)
            button.backgroundColor = bgColor
            button.addTarget(self, action: #selector(dropDownOptionClicked(_:)), for: .touchUpInside)
            button.layer.cornerRadius = cornerRadius
            button.layer.borderWidth = borderWidth
            button.layer.borderColor = borderColor
            button.titleLabel?.font = font
            
            if images != nil {
                button.setBackgroundImage(images![place], for: .normal)
                if imageInsets != nil {
                    button.imageEdgeInsets = imageInsets![place]
                } else if imageInsets == nil && imageInset != nil{
                    button.imageEdgeInsets = imageInset!
                } else {
                    button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
                }
            }
            
            print("Button: \(button), Title: \(String(describing: button.titleLabel?.text)), Target: \(button.allTargets)")
            
            button.isHidden = true
            button.alpha = 0
            
            self.addArrangedSubview(button)
            
            button.translatesAutoresizingMaskIntoConstraints = false
            button.widthAnchor.constraint(equalToConstant: mainFrame.width).isActive = true
            button.heightAnchor.constraint(equalToConstant: mainFrame.height).isActive = true
            
            print("Subviews: \(self.arrangedSubviews)")
            
            y += mainFrame.height
            place += 1
            print("y: \(y)")
        }
    }
    
    @objc func openDropDown(_ sender: UIButton) {
        print("Open DropDownMenu")
        self.arrangedSubviews.forEach { (button) in
            UIView.animate(withDuration: 0.7) {
                button.isHidden = !button.isHidden
                button.alpha = button.alpha == 0 ? 1 : 0
                self.target.view.layoutIfNeeded()
            }
        }
    }
    
    @objc private func dropDownOptionClicked(_ sender: UIButton) {
        let text = sender.titleLabel?.text
        print(text as Any)
        
        currentSelected = text
        print("Value: \(String(describing: value))")
        
        titleButton.setTitle(text, for: .normal)
        openDropDown(sender)
    }
    
    init() {
        super.init(frame: CGRect.zero)
        
        self.translatesAutoresizingMaskIntoConstraints = false
        self.axis = .vertical
    }
    
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Here is the creation in ViewController...

let titleButton = UIButton(frame: CGRect(x: 50, y: 290, width: 100, height: 40))
titleButton.backgroundColor = UIColor.white
titleButton.setTitle("Grade", for: .normal)
titleButton.setTitleColor(UIColor.black, for: .normal)
titleButton.layer.borderWidth = 2
titleButton.layer.cornerRadius = 10
        
let dp = DropDownMenu(options: ["1", "Freshman", "Sophomore", "Junior", "Senior", "College"])
dp.titleButton = titleButton
dp.target = self
dp.borderWidth = 2
dp.spacing = 5
dp.cornerRadius = 10
dp.bgColor = UIColor.white
        
titleButton.addTarget(dp, action: #selector(dp.openDropDown(_:)), for: .touchUpInside)

infoBox.addSubview(titleButton)
infoBox.addSubview(dp)
dp.createDropDownMenu()

The class works as expected.

I really need help on this. No answer is a bad one. This is all of my code.

1 Answer 1

1

You usually do that with a delegate:

class DropDownMenu: UIStackView {
    weak var delegate: DropDownMenuDelegate?

    var value: String! {
        get {
            return currentSelected
        }
        set {
            if currentSelected != newValue {
                currentSelected = newValue
                self.delegate?.valueDidChange(self)
            }
        }
    }
}

protocol DropDownMenuDelegate: class {
    func valueDidChange(_ menu: DropDownMenu)
}

Then in your View Controller:

let dp = DropDownMenu(options: ["1", "Freshman", "Sophomore", "Junior", "Senior", "College"])
dp.delegate = self

(typing this in the blind as I'm away from Xcode so there may be syntax errors)

Sign up to request clarification or add additional context in comments.

1 Comment

This actually really helps. I moved on to a different project, but plan to come back to this one soon enough. Thank you for the response.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.