Introduction
I'm creating an app which uses a custom view in which I have a UIStackView to sort out 5 UIControls. When a user taps one of the UIControls an underscore line gets animated, sliding under the tapped UIControl.
However, for some reason the method/selector for these UIControls no longer gets called. I believe this has to do with that I updated my Mac to the macOS (and Xcode) update released this week (wk.44). (updated from swift 4.2 to swift 4.2.1). Before the updated this animation and selector worked perfectly. But I'm not sure. And I'm now completely stuck on what I'm doing wrong.
Context
I created a playground and scaled down everything as much as I could and the issue persists.
I have tried to define the UIStackView in the global scope of my
SetupView
class but it doesn't change anything. So I believe it is not an issue of the stackView or its subviews being deallocated?Below I've provided my UIControl subclass and my
SetupView
(UIView subclass) that I use. I've created a playground so you may copy paste in Xcode playground to test if you want.
Question
- Why doesn't the method
goalViewControlTapped(_ sender: SetupViewControl)
get called?
Code
import UIKit
import PlaygroundSupport
class SetupViewControl: UIControl {
let titleLabel : UILabel = {
let lbl = UILabel()
lbl.font = UIFont(name: "Futura", size: 14)
lbl.textColor = .white
lbl.backgroundColor = .clear
lbl.textAlignment = .center
lbl.translatesAutoresizingMaskIntoConstraints = false
return lbl
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupLabel()
layer.cornerRadius = 5
}
fileprivate func setupLabel() {
addSubview(titleLabel)
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 5).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -5).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var isHighlighted: Bool {
didSet {
UIView.animate(withDuration: 0.12) {
self.backgroundColor = self.isHighlighted ? UIColor.lightGray : UIColor.clear
}
}
}
}
class SetupView: UIView {
let dataModel : [String] = ["2 weeks", "1 month", "2 months", "6 months", "1 year"]
var selectionLineCenterX : NSLayoutConstraint!
let selectionLine = UIView()
let labelZero = SetupViewControl()
let labelOne = SetupViewControl()
let labelTwo = SetupViewControl()
let labelThree = SetupViewControl()
let labelFour = SetupViewControl()
let labelFive = SetupViewControl()
lazy var controlArray = [self.labelZero, self.labelOne, self.labelTwo, self.labelThree, self.labelFour, self.labelFive]
init(frame: CGRect, color: UIColor) {
super.init(frame: frame)
self.backgroundColor = color
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupView() {
layer.cornerRadius = 0
layer.borderColor = UIColor.black.cgColor
layer.borderWidth = 1
setupLabelText()
setupControlsInStackView()
}
fileprivate func setupLabelText() {
for num in 0...(dataModel.count - 1) {
controlArray[num].titleLabel.text = dataModel[num]
}
}
// let stackView = UIStackView(frame: .zero) I have tried to declare the stackView here but it doesn't fix my issue.
func setupControlsInStackView() {
var stackViewArray = [SetupViewControl]()
for num in 0...(dataModel.count - 1) {
controlArray[num].isUserInteractionEnabled = true
controlArray[num].addTarget(self, action: #selector(goalViewControlTapped(_:)), for: .touchUpInside)
stackViewArray.append(controlArray[num])
}
let stackView = UIStackView(arrangedSubviews: stackViewArray)
stackView.alignment = .fill
stackView.distribution = .fillEqually
stackView.axis = .horizontal
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8).isActive = true
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8).isActive = true
stackView.topAnchor.constraint(equalTo: topAnchor, constant: 15).isActive = true
addSubview(selectionLine)
selectionLine.backgroundColor = .white
selectionLine.translatesAutoresizingMaskIntoConstraints = false
selectionLine.heightAnchor.constraint(equalToConstant: 1).isActive = true
selectionLine.topAnchor.constraint(equalTo: stackView.bottomAnchor).isActive = true
selectionLine.widthAnchor.constraint(equalToConstant: 50).isActive = true
selectionLineCenterX = selectionLine.centerXAnchor.constraint(equalTo: leadingAnchor, constant: -100)
selectionLineCenterX.isActive = true
}
@objc fileprivate func goalViewControlTapped(_ sender: SetupViewControl) {
print("This is not getting printed!!!")
selectionLineCenterX.isActive = false
selectionLineCenterX = selectionLine.centerXAnchor.constraint(equalTo: sender.centerXAnchor)
selectionLineCenterX.isActive = true
UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: .curveEaseIn, animations: {
self.layoutIfNeeded()
}, completion: nil)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let testView = SetupView(frame: .zero, color: UIColor.blue)
view.addSubview(testView)
testView.translatesAutoresizingMaskIntoConstraints = false
testView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
testView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
testView.heightAnchor.constraint(equalToConstant: 100).isActive = true
testView.widthAnchor.constraint(equalToConstant: 365).isActive = true
}
}
// For live view in playground
let vc = ViewController()
vc.preferredContentSize = CGSize(width: 375, height: 812)
PlaygroundPage.current.liveView = vc
Thanks for reading my question.