Adding Custom UIView to TableViewCell - ios

I have been unsuccessful in adding my custom UIView to my TableViewCell. This custom view represents a custom check mark for each table view cell. I am doing my project without a storyboard and I'm not sure how to add this custom UIView to my UITableViewCell programmatically. Here's my code:
class CheckBoxView: UIView {
var isChecked: Bool
var checkBoxImageView: UIImageView
var checkBoxChanged :() -> () = { }
required init?(coder aDecoder: NSCoder) {
self.isChecked = false
self.checkBoxImageView = UIImageView(image: nil)
super.init(coder: aDecoder)
setup()
}
func setup() {
self.layer.borderWidth = 1.0
self.isUserInteractionEnabled = true
self.checkBoxImageView.frame = CGRect(x: 2, y: 2, width: 25, height: 25)
self.addSubview(self.checkBoxImageView)
let selector: Selector = "checkBoxTapped"
let tapRecognizer = UITapGestureRecognizer(target: self, action: selector)
self.addGestureRecognizer(tapRecognizer)
}
func checkBoxTapped() {
self.checkBoxChanged()
}
func markAsChecked() {
self.checkBoxImageView.image = UIImage(named: "new_message_icon")
}
func markAsUnChecked() {
self.checkBoxImageView.image = nil
}
}
Here's my TableViewCell:
class AddContactsCell: UITableViewCell {
let profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.layer.cornerRadius = 20
imageView.layer.masksToBounds = true
imageView.contentMode = .scaleAspectFill
return imageView
}()
let checkBox: CheckBoxView = {
let view = UIView() as! CheckBoxView
view.backgroundColor = UIColor.blue
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 16
view.layer.masksToBounds = true
return view
}()
override func layoutSubviews() {
super.layoutSubviews()
textLabel?.frame = CGRect(x: 100, y: textLabel!.frame.origin.y - 2, width: textLabel!.frame.width, height: textLabel!.frame.height)
detailTextLabel?.frame = CGRect(x: 101, y: detailTextLabel!.frame.origin.y + 1, width: detailTextLabel!.frame.width, height: detailTextLabel!.frame.height)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
addSubview(profileImageView)
self.addSubview(checkBox)
//ios 9 constraint anchors
//need x,y,width,height anchors
profileImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 50).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
checkBox.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true
checkBox.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
checkBox.widthAnchor.constraint(equalToConstant: 30).isActive = true
checkBox.heightAnchor.constraint(equalToConstant: 30).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I would really appreciate if you could tell me where I'm going wrong with adding the UIView.

you should instanciate your CheckBoxView and not cast a normal UIView to your CheckBoxView
change this line:
let view = UIView() as! CheckBoxView
to this line
let view = CheckBoxView()

Related

Dropping shadow inside UITableView Cell doesn't work in Swift

My project doesn't use Storyboards since it's using CleanSwift architecture.
Every views are built programmatically. Here's my table cell class.
class LiveScoreCell: UITableViewCell {
var data: LiveScores.Data? {
didSet {
leagueLogo.setImage(data?.leagueLogo)
}
}
var container: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 10
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = .zero
view.layer.shadowOpacity = 0.6
view.layer.shadowRadius = 10
view.layer.shadowPath = UIBezierPath(rect: view.bounds).cgPath
view.layer.borderWidth = 1
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var leagueLogo: UIImageView = {
let imgView = UIImageView()
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
selectionStyle = .none
setupViews()
}
override func prepareForReuse() {
super.prepareForReuse()
}
func setupViews() {
addSubview(container)
container.topAnchor.constraint(equalTo: self.topAnchor, constant: 8).isActive = true
container.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8).isActive = true
container.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8).isActive = true
container.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8).isActive = true
addSubview(leagueLogo)
leagueLogo.topAnchor.constraint(equalTo: container.topAnchor, constant: 8).isActive = true
leagueLogo.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 8).isActive = true
leagueLogo.widthAnchor.constraint(equalToConstant: 26).isActive = true
leagueLogo.heightAnchor.constraint(equalToConstant: 26).isActive = true
}
}
And the result is ..
Only border involves.. Any idea why is this happening?
As of this line
view.layer.shadowPath = UIBezierPath(rect: view.bounds).cgPath
runs when bounds is zero so make it inside
override func layoutSubviews() {
super.layoutSubviews()
container.layer.shadowPath = UIBezierPath(rect: container.bounds).cgPath
}

How to add gravity to UIViews in a UITableViewCell?

I am trying to animate a few UIViews by having gravity act on them. Ideally, each view would stay inside the UITableViewCell bounds and they would bounce off of each other and the walls like boundaries. However, when I run this code, the UIView's just kind of float in place, only moving if another view happens to populate in the same spot.
class AnimateTableViewCell: UITableViewCell {
private var animator: UIDynamicAnimator!
private var gravity: UIGravityBehavior!
private var collision: UICollisionBehavior!
private var views = [UIView]()
override func awakeFromNib() {
super.awakeFromNib()
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
animator = UIDynamicAnimator(referenceView: self.contentView)
let items = [UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill")]
for item in items {
let size = Int.random(in: 75 ... 180)
self.setUpView(view: UIView(frame: CGRect(x: 100, y: 100, width: size, height: size)), image: item!, size: size/2)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func applyGravity(to item: UIView) {
gravity = UIGravityBehavior(items: [item])
animator.addBehavior(gravity)
collision = UICollisionBehavior(items: views)
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
let bounce = UIDynamicItemBehavior(items: views)
bounce.elasticity = 0.3
}
private func setUpView(view: UIView, image: UIImage, size: Int) {
contentView.addSubview(view)
view.backgroundColor = image.averageColor
view.layer.cornerRadius = view.frame.height/2
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.heightAnchor.constraint(equalToConstant: CGFloat(size)),
imageView.widthAnchor.constraint(equalToConstant: CGFloat(size)),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
views.append(view)
applyGravity(to: view)
}
}
There are two main problems.
First, the collision behavior is getting in your way. Comment out this line:
animator.addBehavior(collision)
Now at least you will see the gravity operate.
Second, you are saying
gravity = UIGravityBehavior(items: [item])
animator.addBehavior(gravity)
multiple times, once per item. That's wrong. You must have just one gravity behavior that embraces all the items.
I got a fair-to-middling result just by rearranging some of your code and changing a few of the magic numbers; this should get you started, at least (I used a table view with just one cell, quite tall in height):
class AnimateTableViewCell: UITableViewCell {
private var animator: UIDynamicAnimator!
private var gravity = UIGravityBehavior()
private var collision = UICollisionBehavior()
private var views = [UIView]()
override func awakeFromNib() {
super.awakeFromNib()
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
animator = UIDynamicAnimator(referenceView: self.contentView)
let items = [UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill")]
for item in items {
let size = Int.random(in: 20...40)
self.setUpView(view: UIView(frame: CGRect(x: 100, y: 100, width: size, height: size)), image: item!, size: size)
}
animator.addBehavior(gravity)
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
let bounce = UIDynamicItemBehavior(items: views)
bounce.elasticity = 0.3
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func applyGravity(to item: UIView) {
gravity.addItem(item)
collision.addItem(item)
}
private func setUpView(view: UIView, image: UIImage, size: Int) {
contentView.addSubview(view)
view.backgroundColor = .red
view.layer.cornerRadius = view.frame.height/2
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.heightAnchor.constraint(equalToConstant: CGFloat(size)),
imageView.widthAnchor.constraint(equalToConstant: CGFloat(size)),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
views.append(view)
applyGravity(to: view)
}
}

Strange black corners when using draw(_ rect:) function

If I put the code for my UIBezierPath inside the draw(_ rect:) function I get these strange very thin black corners around the view and the tail. When dragging the view (e.g. within a presented view controller) these thin lines also start flickering. I assume it's a weird rendering bug. Does anyone know if there is a way to fix this?
class RenderingView: UIView {
lazy var backgroundView: UIView = {
let view = UIView()
view.layer.cornerRadius = 8
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var shadowView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var textLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Rendering Bug"
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
backgroundColor = .clear
backgroundView.backgroundColor = .yellow
layer.borderWidth = 0
setupLayout()
}
private func setupLayout() {
[shadowView, backgroundView, textLabel].forEach(addSubview)
backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
backgroundView.topAnchor.constraint(equalTo: topAnchor).isActive = true
backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
shadowView.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor).isActive = true
shadowView.topAnchor.constraint(equalTo: backgroundView.topAnchor).isActive = true
shadowView.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor).isActive = true
shadowView.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor).isActive = true
textLabel.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: 10).isActive = true
textLabel.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor, constant: -10).isActive = true
textLabel.topAnchor.constraint(equalTo: backgroundView.topAnchor, constant: 10).isActive = true
textLabel.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor, constant: -10).isActive = true
}
override func draw(_ rect: CGRect) {
shapeBackground()
}
private func shapeBackground() {
let tailLayer = CAShapeLayer()
let bezierPath = UIBezierPath(roundedRect: CGRect(x: backgroundView.bounds.minX,
y: backgroundView.bounds.minY,
width: backgroundView.bounds.width,
height: backgroundView.bounds.height - 12),
cornerRadius: 8)
let shadowBezierPath = UIBezierPath(roundedRect: CGRect(x: backgroundView.bounds.minX + 5,
y: backgroundView.bounds.minY + 10,
width: backgroundView.bounds.width - 10,
height: backgroundView.bounds.height - 12 - 10),
cornerRadius: 8)
[bezierPath, shadowBezierPath].forEach {
$0.move(to: CGPoint(x: backgroundView.bounds.midX - 12, y: backgroundView.bounds.maxY - 12))
$0.addLine(to: CGPoint(x: backgroundView.bounds.midX, y: backgroundView.bounds.maxY))
$0.addLine(to: CGPoint(x: backgroundView.bounds.midX + 12, y: backgroundView.bounds.maxY - 12))
$0.fill()
$0.close()
}
tailLayer.path = bezierPath.cgPath
tailLayer.fillColor = UIColor.white.cgColor
shadowView.layer.shadowPath = shadowBezierPath.cgPath
shadowView.layer.cornerRadius = 8
backgroundView.layer.masksToBounds = true
backgroundView.layer.mask = tailLayer
}
}
EDIT:
Turns out I had to use addClip() on the bezier paths to get rid of these corners
Not sure if this is what you are aiming for, but it looks flawless when you move the shapeBackground() method out of draw(_ rect:) and do some slight modifications.
I modified some of your drawing routines inside shapeBackground(), and moved the function into layoutSubviews() to calculate position of the tail from the frame made by constraints. I also added some variables for tailWidth, & tailHeight.
Like so:
class RenderingView: UIView {
lazy var backgroundView: UIView = {
let view = UIView()
view.layer.cornerRadius = 8
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var shadowView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var textLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "No Rendering Bug"
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
backgroundColor = .clear
backgroundView.backgroundColor = .systemTeal
//backgroundView.frame.size = CGSize(width: 100, height: 100)
layer.borderWidth = 0
setupLayout()
}
private func setupLayout() {
[shadowView, backgroundView, textLabel].forEach(addSubview)
backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
backgroundView.topAnchor.constraint(equalTo: topAnchor).isActive = true
backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
shadowView.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor).isActive = true
shadowView.topAnchor.constraint(equalTo: backgroundView.topAnchor).isActive = true
shadowView.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor).isActive = true
shadowView.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor).isActive = true
textLabel.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: 10).isActive = true
textLabel.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor, constant: -10).isActive = true
textLabel.topAnchor.constraint(equalTo: backgroundView.topAnchor, constant: 10).isActive = true
textLabel.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor, constant: -10).isActive = true
}
override func didMoveToWindow() {
super.didMoveToWindow()
}
override func layoutSubviews() {
super.layoutSubviews()
shapeBackground(color: UIColor.systemTeal)
}
override func draw(_ rect: CGRect) {
super.draw(rect)
}
private func shapeBackground(color: UIColor) {
let tailLayer = CAShapeLayer()
tailLayer.name = "tailLayer"
let tailWidth: CGFloat = 16
let tailHeight: CGFloat = 10
let bezierPath = UIBezierPath()
let shadowBezierPath = UIBezierPath()
[bezierPath, shadowBezierPath].forEach {
$0.move(to: CGPoint(x: 0, y: 0))
$0.addLine(to: CGPoint(x: tailWidth / 2, y: tailHeight))
$0.addLine(to: CGPoint(x: tailWidth, y: 0))
$0.fill()
$0.close()
}
tailLayer.path = bezierPath.cgPath
tailLayer.fillColor = color.cgColor
shadowView.layer.shadowPath = shadowBezierPath.cgPath
shadowView.layer.cornerRadius = 8
print(backgroundView.bounds.width)
tailLayer.frame = CGRect(x: (backgroundView.bounds.width - tailWidth) / 2,
y: backgroundView.bounds.maxY,
width: tailWidth,
height: tailHeight)
backgroundView.layer.masksToBounds = false
backgroundView.layer.addSublayer(tailLayer)
}
}

UIButton in Collection View Cell not receiving Touch Up Inside event

I am trying to setup a Carousel-like UI with buttons in each carousel cell. I am using a Collection View to do this. The buttons show up in the cell, but do not seem to respond to the touch up inside event which should run tapped() and return "TAPPED!". Here is the code for the Collection View Cell which includes the button. Thanks for the help!
CarouselCollectionViewCell.swift
import UIKit
import Foundation
class CarouselCollectionViewCell: UICollectionViewCell {
static let identifier = "CarouselCollectionViewCell"
#objc func tapped() {
print("TAPPED!")
}
var mainView : UIView = {
var mainCellView = UIView()
mainCellView.translatesAutoresizingMaskIntoConstraints = false
return mainCellView
}()
var remindButton : UIButton = {
var textView = UIButton()
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(mainView)
mainView.addSubview(remindButton)
mainView.backgroundColor = .white
//Style
mainView.layer.cornerRadius = 8
mainView.layer.masksToBounds = true
// Constraints
mainView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
mainView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
mainView.heightAnchor.constraint(equalToConstant: 360).isActive = true
mainView.widthAnchor.constraint(equalToConstant: 290).isActive = true
self.remindButton.backgroundColor = UIColor(red: 69.0/255.0, green: 198.0/255.0, blue: 255.0/255.0, alpha: 1.0)
self.remindButton.layer.cornerRadius = 20
self.remindButton.layer.masksToBounds = true
self.remindButton.bottomAnchor.constraint(equalTo: self.mainView.bottomAnchor, constant: -30).isActive = true
self.remindButton.centerXAnchor.constraint(equalTo: self.mainView.centerXAnchor).isActive = true
self.remindButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
self.remindButton.widthAnchor.constraint(equalToConstant: 175).isActive = true
self.remindButton.setTitle("Add Reminder", for: .normal)
self.remindButton.addTarget(self, action: #selector(self.tapped), for: .touchUpInside)
}
override func layoutSubviews() {
super.layoutSubviews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Swift: UIStackView of UIControls with selector method that doesn't fire

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.
Does your UIStackView show as having an ambiguous layout when you open the view debugger? If so, that may be causing the internal views to not receive the touch events.
You can provide UIStackView with either:
x and y constraints only
or
x, y, width and height.
In the above case the height constraint is missing.

Resources