Nothing happens when clicking UIButton - ios

i've created a subclass of UIView which contain a SwitchButton, however even though i have added a target there is still no reaction/print when i tap the button. How come is that?
viewController
self.tradeView = TradeView()
self.tradeView.translatesAutoresizingMaskIntoConstraints = false
self.tradeView.backgroundColor = Color.theme.value
self.view.addSubview(self.tradeView)
subclass
class TradeView: UIView {
var waveView: UIImageView!
var bottomView: UIView!
var topView: UIView!
var centerView: UIView!
var switchButton: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUp()
}
func setUp() {
waveView = UIImageView()
waveView.translatesAutoresizingMaskIntoConstraints = false
waveView.isUserInteractionEnabled = false
waveView.image = UIImage(named: "wave")
self.addSubview(waveView)
topView = UIImageView()
topView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(topView)
centerView = UIImageView()
centerView.isUserInteractionEnabled = false
centerView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(centerView)
bottomView = UIImageView()
bottomView.isUserInteractionEnabled = false
bottomView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(bottomView)
waveView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 1).isActive = true
waveView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
waveView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
waveView.heightAnchor.constraint(equalToConstant: 32).isActive = true
waveView.topAnchor.constraint(equalTo: self.bottomView.bottomAnchor).isActive = true
topView.bottomAnchor.constraint(equalTo: self.centerView.topAnchor).isActive = true
topView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
topView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
topView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
topView.heightAnchor.constraint(equalTo: bottomView.heightAnchor).isActive = true
centerView.bottomAnchor.constraint(equalTo: self.bottomView.topAnchor).isActive = true
centerView.topAnchor.constraint(equalTo: self.topView.bottomAnchor).isActive = true
centerView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
centerView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
centerView.heightAnchor.constraint(equalToConstant: 46).isActive = true
bottomView.bottomAnchor.constraint(equalTo: self.waveView.topAnchor).isActive = true
bottomView.topAnchor.constraint(equalTo: self.centerView.bottomAnchor).isActive = true
bottomView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
bottomView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
bottomView.heightAnchor.constraint(equalTo: self.topView.heightAnchor).isActive = true
setUpCenterView()
}
func setUpCenterView() {
let borderView = UIView()
borderView.translatesAutoresizingMaskIntoConstraints = false
borderView.backgroundColor = Color.lightButton.withAlpha(0.3)
self.centerView.addSubview(borderView)
self.switchButton = UIButton(type: .custom)
switchButton.translatesAutoresizingMaskIntoConstraints = false
self.switchButton.setImage(UIImage(named: "switch"), for: .normal)
self.switchButton.addTarget(self, action: #selector(switchExchange), for: UIControlEvents.touchUpInside)
self.centerView.addSubview(switchButton)
borderView.centerYAnchor.constraint(equalTo: self.centerView.centerYAnchor).isActive = true
borderView.leftAnchor.constraint(equalTo: self.centerView.leftAnchor, constant: 24).isActive = true
borderView.rightAnchor.constraint(equalTo: self.switchButton.leftAnchor, constant: -24).isActive = true
borderView.heightAnchor.constraint(equalToConstant: 1).isActive = true
self.switchButton.centerYAnchor.constraint(equalTo: self.centerView.centerYAnchor).isActive = true
self.switchButton.leftAnchor.constraint(equalTo: borderView.rightAnchor, constant: 24).isActive = true
self.switchButton.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -24).isActive = true
self.switchButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
self.switchButton.widthAnchor.constraint(equalToConstant: 40).isActive = true
}
#objc func switchExchange() {
print("swap")
(bottomObj,topObj) = (topObj,bottomObj)
}
}

Your centerView has isUserInteractionEnabled set to false. This prevents all its subviews, including switchButton, from interacting.
Replace
centerView.isUserInteractionEnabled = false
with
centerView.isUserInteractionEnabled = true

Related

How to add UIView Gesture - Programmatically UIView

I have searched a lot about adding a gesture on UIView when it is tapped. There are many solutions but none of them worked for me.
I have made UIView class programmatically and using the view in different classes.
Here is my class of UIView:
class PaymentServiceView: UIView {
private let views: UIView = {
let view = UIView()
view.backgroundColor = .white
// view.layer.maskedCorners = [.layerMinXMinYCorner,.layerMaxXMinYCorner]
view.layer.borderColor = UIColor.gray.cgColor
view.layer.shadowOpacity = 0.3
view.layer.shadowColor = UIColor.gray.cgColor
view.layer.shadowRadius = 10
view.layer.borderWidth = 0.1
view.layer.cornerRadius = 20
view.isUserInteractionEnabled = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let titleLbl: UILabel = {
var label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.textColor = UIColor.black
label.font = UIFont(name: AppFontName.circularStdRegular, size: 18)
label.clipsToBounds = true
return label
}()
private let subLbl: UILabel = {
var label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.textColor = UIColor.gray
label.numberOfLines = 0
label.textAlignment = .left
label.font = UIFont(name: AppFontName.robotoRegular, size: 15)
label.clipsToBounds = true
return label
}()
private let image: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
private let btnImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.image = UIImage(named: IconName.chevron_down)?.transform(withNewColor: UIColor.btnGray)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
init(titleLabel: String, subTitleLabel: String, imageName: String) {
super.init(frame: CGRect.zero)
self.addSubview(views)
self.views.addSubview(btnImage)
self.views.addSubview(titleLbl)
self.views.addSubview(image)
self.views.addSubview(subLbl)
titleLbl.text = titleLabel
image.image = UIImage(named: imageName)
subLbl.text = subTitleLabel
setupConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupConstraints() {
self.views.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
self.views.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
self.views.heightAnchor.constraint(equalToConstant: 150).isActive = true
self.views.widthAnchor.constraint(equalToConstant: 320).isActive = true
self.image.centerYAnchor.constraint(equalTo: self.views.centerYAnchor).isActive = true
self.image.leadingAnchor.constraint(equalTo: self.views.leadingAnchor, constant: 15).isActive = true
self.image.widthAnchor.constraint(equalToConstant: 30).isActive = true
self.image.heightAnchor.constraint(equalToConstant: 30).isActive = true
self.titleLbl.centerYAnchor.constraint(equalTo: self.views.centerYAnchor, constant: -35).isActive = true
self.titleLbl.leadingAnchor.constraint(equalTo: image.trailingAnchor, constant: 15).isActive = true
self.subLbl.topAnchor.constraint(equalTo: titleLbl.bottomAnchor, constant: 5).isActive = true
self.subLbl.leadingAnchor.constraint(equalTo: image.trailingAnchor, constant: 15).isActive = true
self.subLbl.trailingAnchor.constraint(equalTo: btnImage.leadingAnchor, constant: -15).isActive = true
btnImage.topAnchor.constraint(equalTo: views.topAnchor, constant: 55).isActive = true
btnImage.rightAnchor.constraint(equalTo: views.rightAnchor, constant: -10).isActive = true
btnImage.heightAnchor.constraint(equalToConstant: 10).isActive = true
}
}
Now Im using this UIView class in PaymentServicesViewController
class PaymentServicesViewController: UIViewController {
private (set) lazy var headerView: HeaderView = { [unowned self] in
let view = HeaderView.init(titleLbl: Headings.paymentService, closeAction: {
self.navigationController?.popViewController(animated: true)
}, nextAction: {
print("next")
}, previousAction: {
self.navigationController?.popViewController(animated: true)
})
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let fundTransferView: PaymentServiceView = {
let view = PaymentServiceView(titleLabel: Headings.fundTransfer, subTitleLabel: Description.fundTransferDecription , imageName: IconName.fundImage )
view.isUserInteractionEnabled = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let subscriptionView: PaymentServiceView = {
let view = PaymentServiceView(titleLabel: Headings.subscribe, subTitleLabel: Description.subscriptionDescription, imageName: IconName.subImage )
view.isUserInteractionEnabled = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let billPaymentView: PaymentServiceView = {
let view = PaymentServiceView(titleLabel: Headings.billPayment, subTitleLabel: Description.billPaymentDescription , imageName: IconName.billImage )
view.isUserInteractionEnabled = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .gray2
let fundtrasnferGesture = UITapGestureRecognizer(target: self, action: #selector(fundTranferTapped))
fundTransferView.isUserInteractionEnabled = true
self.fundTransferView.addGestureRecognizer(fundtrasnferGesture)
let subscribeGesture = UITapGestureRecognizer(target: self, action: #selector(subscribeTapped))
subscriptionView.isUserInteractionEnabled = true
self.subscriptionView.addGestureRecognizer(subscribeGesture)
let billPaymentGesture = UITapGestureRecognizer(target: self, action: #selector(billPaymentTapped))
fundTransferView.isUserInteractionEnabled = true
self.billPaymentView.addGestureRecognizer(billPaymentGesture)
view.addSubview(headerView)
view.addSubview(subscriptionView)
view.addSubview(fundTransferView)
view.addSubview(billPaymentView)
setupConstraint()
}
#objc func fundTranferTapped(sender: UITapGestureRecognizer) {
print("FundTransfer Tapped.")
}
#objc func subscribeTapped(sender: UITapGestureRecognizer) {
print("Subscribe Tapped.")
}
#objc func billPaymentTapped(sender: UITapGestureRecognizer) {
print("BillPayment Tapped.")
}
private func setupConstraint() {
headerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
headerView.heightAnchor.constraint(equalToConstant: 100).isActive = true
subscriptionView.trailingAnchor.constraint(equalTo: fundTransferView.trailingAnchor, constant: 0).isActive = true
subscriptionView.leadingAnchor.constraint(equalTo: fundTransferView.leadingAnchor, constant: 0).isActive = true
subscriptionView.bottomAnchor.constraint(equalTo: fundTransferView.topAnchor, constant: -130).isActive = true
fundTransferView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
fundTransferView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
billPaymentView.leadingAnchor.constraint(equalTo: fundTransferView.leadingAnchor, constant: 0).isActive = true
billPaymentView.trailingAnchor.constraint(equalTo: fundTransferView.trailingAnchor).isActive = true
billPaymentView.topAnchor.constraint(equalTo: fundTransferView.bottomAnchor, constant: 130).isActive = true
}
}
I know there is a small mistake I'm doing but not sure. Help would be appreciated, Thank you.
You are missing a couple constraints...
If you add this at the end of viewDidLoad():
subscriptionView.clipsToBounds = true
fundTransferView.clipsToBounds = true
billPaymentView.clipsToBounds = true
You'll see that the views "disappear":
because they have no Width or Height constraints (so their size is .zero).
In setupConstraints() in your PaymentServiceView class, add these two lines:
self.widthAnchor.constraint(equalTo: self.views.widthAnchor).isActive = true
self.heightAnchor.constraint(equalTo: self.views.heightAnchor).isActive = true
Now, the PaymentServiceView will be the same Width and Height as self.views view.
However, now that the views have Heights:
your layout needs to be adjusted.
Change the .clipsToBounds back to false (remove those added lines) so the shadows won't be clipped, and change these constraints in your controller (adjust the 15 and -15 to your liking):
//subscriptionView.bottomAnchor.constraint(equalTo: fundTransferView.topAnchor, constant: -130).isActive = true
subscriptionView.bottomAnchor.constraint(equalTo: fundTransferView.topAnchor, constant: 15).isActive = true
//billPaymentView.topAnchor.constraint(equalTo: fundTransferView.bottomAnchor, constant: 130).isActive = true
billPaymentView.topAnchor.constraint(equalTo: fundTransferView.bottomAnchor, constant: -15).isActive = true
and we get:
Now, because the views have a size, the Tap Gestures will work.

How do I make my collectionView UICollectionViewCell a dynamic height?

I have a collectionview and the cells in the collectionview are stretching their height. I used UICollectionViewCompositionalLayout so similar questions asked on this site did not seem to apply.
Here is where I create my UICollectionViewCompositionalLayout
private func configureLayout() -> UICollectionViewCompositionalLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(400))
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
}
Here is the View I am trying to display in the cell.
class PostCell: UICollectionViewCell {
static let reuseIdentifier = String(describing: PostCell.self)
private lazy var textPost : TextPostView = {
let textPost = TextPostView()
textPost.translatesAutoresizingMaskIntoConstraints = false
addSubview(textPost)
textPost.topAnchor.constraint(equalTo: topAnchor).isActive = true
textPost.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
textPost.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
textPost.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
return textPost
}()
private lazy var mediaPost : MediaPostView = {
let mediaPost = MediaPostView()
mediaPost.translatesAutoresizingMaskIntoConstraints = false
addSubview(mediaPost)
mediaPost.topAnchor.constraint(equalTo: topAnchor).isActive = true
mediaPost.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
mediaPost.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
mediaPost.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
return mediaPost
}()
private lazy var eventPost : EventPostView = {
let eventPost = EventPostView()
eventPost.translatesAutoresizingMaskIntoConstraints = false
addSubview(eventPost)
eventPost.topAnchor.constraint(equalTo: topAnchor).isActive = true
eventPost.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
eventPost.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
eventPost.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
return eventPost
}()
func setData(_ presentable: PostPresentable) {
switch presentable.type {
case .text:
eventPost.isHidden = true
mediaPost.isHidden = true
textPost.isHidden = false
textPost.setData(presentable)
case .media:
eventPost.isHidden = true
mediaPost.isHidden = false
textPost.isHidden = true
mediaPost.setData(presentable)
case .event:
eventPost.isHidden = false
mediaPost.isHidden = true
textPost.isHidden = true
eventPost.setData(presentable)
}
}
}
Here is the TextPostView that I display in the cell
import Foundation
import UIKit
class TextPostView: UIView {
lazy var headerView: PostHeaderView = {
let headerView = PostHeaderView()
headerView.translatesAutoresizingMaskIntoConstraints = false
addSubview(headerView)
let margin: CGFloat = 2
headerView.topAnchor.constraint(equalTo: topAnchor, constant: margin).isActive = true
headerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: margin).isActive = true
headerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: margin).isActive = true
return headerView
}()
lazy var descriptionView: UILabel = {
let description = UILabel()
description.translatesAutoresizingMaskIntoConstraints = false
description.font = UIFont.preferredFont(forTextStyle: .body)
description.numberOfLines = 0
let headerViewLayoutGuide = headerView.layoutGuide(self)
addSubview(description)
let margin: CGFloat = 8
description.topAnchor.constraint(equalTo: headerViewLayoutGuide.bottomAnchor, constant: margin).isActive = true
description.leadingAnchor.constraint(equalTo: leadingAnchor,constant: margin).isActive = true
description.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -margin).isActive = true
return description
}()
lazy var footerView: PostFooterView = {
let footer = PostFooterView()
footer.translatesAutoresizingMaskIntoConstraints = false
addSubview(footer)
let descriptionViewLayoutGuide = descriptionView.layoutGuide(self)
footer.topAnchor.constraint(equalTo: descriptionViewLayoutGuide.bottomAnchor, constant: 8).isActive = true
footer.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
footer.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
footer.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
return footer
}()
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
initialize()
}
private func initialize() {
layer.borderColor = UIColor.gray.cgColor
layer.borderWidth = 1
layer.cornerRadius = 16
}
func setData(_ presentable: PostPresentable) {
headerView.setData(presentable.header)
footerView.setData(presentable.footer)
descriptionView.text = presentable.description
}
}
The PostHeaderView that the post uses
import Foundation
import UIKit
import SDWebImage
class PostHeaderView: UIView {
private static let horizontalMargin: CGFloat = 8
private static let iconHeight: CGFloat = 20
private lazy var date: UILabel = {
let label = UILabel()
label.font = UIFont.preferredFont(forTextStyle: .caption2)
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: PostHeaderView.horizontalMargin).isActive = true
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
return label
}()
private lazy var flairsContainer: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.distribution = .fill
stackView.alignment = .trailing
stackView.translatesAutoresizingMaskIntoConstraints = false
let dateLayoutGuide = UILayoutGuide()
let shareLayoutGuide = UILayoutGuide()
addLayoutGuide(dateLayoutGuide)
addLayoutGuide(shareLayoutGuide)
addSubview(stackView)
dateLayoutGuide.trailingAnchor.constraint(equalTo: date.trailingAnchor).isActive = true
shareLayoutGuide.leadingAnchor.constraint(equalTo: shareButton.leadingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: dateLayoutGuide.trailingAnchor, constant: 16).isActive = true
stackView.trailingAnchor.constraint(equalTo: shareLayoutGuide.leadingAnchor, constant: -16).isActive = true
stackView.heightAnchor.constraint(equalToConstant: PostHeaderView.iconHeight).isActive = true
return stackView
}()
private lazy var title: UILabel = {
let title = UILabel()
title.translatesAutoresizingMaskIntoConstraints = false
title.font = UIFont.preferredFont(forTextStyle: .title1)
let avatarLayoutGuide = avatar.layoutGuide(self)
addSubview(title)
title.leadingAnchor.constraint(equalTo: avatarLayoutGuide.trailingAnchor, constant: 4).isActive = true
title.trailingAnchor.constraint(equalTo: trailingAnchor, constant: PostHeaderView.horizontalMargin).isActive = true
title.centerYAnchor.constraint(equalTo: avatarLayoutGuide.centerYAnchor).isActive = true
return title
}()
private lazy var subHeader: UILabel = {
let subHeader = UILabel()
subHeader.translatesAutoresizingMaskIntoConstraints = false
subHeader.font = UIFont.preferredFont(forTextStyle: .caption1)
let titleLayoutGuide = title.layoutGuide(self)
addSubview(subHeader)
subHeader.topAnchor.constraint(equalTo: titleLayoutGuide.bottomAnchor, constant: 0).isActive = true
subHeader.leadingAnchor.constraint(equalTo: titleLayoutGuide.leadingAnchor).isActive = true
return subHeader
}()
private lazy var checkMark: UIImageView = {
let checkMark = UIImageView()
checkMark.translatesAutoresizingMaskIntoConstraints = false
let image = UIImage(named: "VerifiedBadge")
checkMark.image = image
let subHeaderLayoutGuide = subHeader.layoutGuide(self)
addSubview(checkMark)
checkMark.leadingAnchor.constraint(equalTo: subHeaderLayoutGuide.trailingAnchor).isActive = true
checkMark.centerYAnchor.constraint(equalTo: subHeaderLayoutGuide.centerYAnchor).isActive = true
return checkMark
}()
private lazy var menuButton: UIButton = {
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setImage(UIImage(named: "menu"), for: .normal)
addSubview(button)
button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -PostHeaderView.horizontalMargin).isActive = true
button.topAnchor.constraint(equalTo: topAnchor).isActive = true
button.heightAnchor.constraint(equalToConstant: PostHeaderView.iconHeight).isActive = true
return button
}()
private lazy var shareButton: UIButton = {
let shareButton = UIButton()
shareButton.translatesAutoresizingMaskIntoConstraints = false
let buttonImage = UIImage(systemName: "square.and.arrow.up")?.withRenderingMode(.alwaysTemplate)
shareButton.setImage(buttonImage, for: .normal)
shareButton.tintColor = UIColor.black
let menuLayoutGuide = UILayoutGuide()
addLayoutGuide(menuLayoutGuide)
addSubview(shareButton)
menuLayoutGuide.leadingAnchor.constraint(equalTo: menuButton.leadingAnchor).isActive = true
shareButton.trailingAnchor.constraint(equalTo: menuLayoutGuide.leadingAnchor, constant: -16).isActive = true
shareButton.topAnchor.constraint(equalTo: topAnchor).isActive = true
shareButton.heightAnchor.constraint(equalToConstant: 20).isActive = true
return shareButton
}()
private lazy var avatar: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
let imageViewSize: CGFloat = 52
imageView.layer.cornerRadius = imageViewSize / 2
imageView.clipsToBounds = true
let dateLayoutGuide = UILayoutGuide()
addLayoutGuide(dateLayoutGuide)
addSubview(imageView)
dateLayoutGuide.bottomAnchor.constraint(equalTo: date.bottomAnchor).isActive = true
imageView.heightAnchor.constraint(equalToConstant: imageViewSize).isActive = true
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
imageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: PostHeaderView.horizontalMargin).isActive = true
imageView.topAnchor.constraint(equalTo: dateLayoutGuide.bottomAnchor, constant: 2).isActive = true
imageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func setData(_ presentable: PostHeaderPresentable) {
date.text = presentable.date
avatar.sd_setImage(with: presentable.avatarImageUrl)
title.text = presentable.title
addFlairs(presentable.flairs)
menuButton.isHidden = false
shareButton.isHidden = false
if let subheadline = presentable.subheadline {
subHeader.isHidden = subheadline.text.isEmpty
subHeader.text = subheadline.text
checkMark.isHidden = !subheadline.verified
} else {
checkMark.isHidden = true
subHeader.isHidden = true
}
}
private func addFlairs(_ flairImages: [UIImage]) {
flairsContainer.removeAllArrangedSubviews()
for flairImage in flairImages {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = flairImage
imageView.contentMode = .scaleAspectFill
flairsContainer.addArrangedSubview(imageView)
imageView.heightAnchor.constraint(equalToConstant: PostHeaderView.iconHeight).isActive = true
imageView.widthAnchor.constraint(equalToConstant: PostHeaderView.iconHeight).isActive = true
}
}
}
The PostFooterView
class PostFooterView: UIView {
private static let horizontalMargin: CGFloat = 8
private static let verticalMargin: CGFloat = 16
private lazy var location: UILabel = {
let label = UILabel()
label.font = UIFont.preferredFont(forTextStyle: .subheadline)
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -PostFooterView.horizontalMargin).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -PostFooterView.verticalMargin).isActive = true
return label
}()
private lazy var likeButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
let likeImageSelected = UIImage(named: "Like")?.withRenderingMode(.alwaysTemplate)
let likeImage = UIImage(named: "LikeStroke")?.withRenderingMode(.alwaysTemplate)
button.setImage(likeImageSelected, for: .selected)
button.setImage(likeImage, for: .normal)
button.tintColor = UIColor.black
addSubview(button)
button.leadingAnchor.constraint(equalTo: leadingAnchor, constant: PostFooterView.horizontalMargin).isActive = true
button.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -PostFooterView.verticalMargin).isActive = true
return button
}()
private lazy var dislikeButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
let dislikeImageSelected = UIImage(named: "Dislike")?.withRenderingMode(.alwaysTemplate)
let dislikeImage = UIImage(named: "DislikeStroke")?.withRenderingMode(.alwaysTemplate)
button.setImage(dislikeImageSelected, for: .selected)
button.setImage(dislikeImage, for: .normal)
button.tintColor = UIColor.black
addSubview(button)
let likeButtonLayoutGuide = likeButton.layoutGuide(self)
button.leadingAnchor.constraint(equalTo: likeButtonLayoutGuide.trailingAnchor, constant: 8).isActive = true
button.bottomAnchor.constraint(equalTo: likeButtonLayoutGuide.bottomAnchor).isActive = true
return button
}()
private lazy var navButton : UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
let navigateImage = UIImage(named: "Navigate")?.withRenderingMode(.alwaysTemplate)
button.setImage(navigateImage, for: .normal)
button.setTitle("Navigate", for: .normal)
button.tintColor = UIColor.black
button.setTitleColor(UIColor.black, for: .normal)
addSubview(button)
let likeButtonLayoutGuide = likeButton.layoutGuide(self)
topAnchor.constraint(equalTo: button.topAnchor).isActive = true
button.leadingAnchor.constraint(equalTo: leadingAnchor, constant: PostFooterView.horizontalMargin).isActive = true
button.bottomAnchor.constraint(equalTo: likeButtonLayoutGuide.topAnchor, constant: -20).isActive = true
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func setData(_ presentable: PostFooterPresentable) {
location.text = presentable.location
navButton.isHidden = !presentable.showNavigation
likeButton.isSelected = presentable.reaction == .like
dislikeButton.isSelected = presentable.reaction == .dislike
}
}
Here is a screenshot of how it looks

Setting UITextField heightAnchor to 0 does not work on iOS 15

I have an iOS application where i have a textfield and a button and on tap of button i have to hide the textfield.
I am setting heightAnchor to 0 on tap of button. Everything is working fine on iOS 14(14.5) but does not work(does not hide the text field) on iOS 15. Also, I have tried setting up the isHidden property on UITextField but it does not work.
Can you please help tell if something changed or i am doing something wrong. Thank you.
Code reference:
import UIKit
class ViewController: UIViewController {
private lazy var mytextFeild: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.text = "Hello world"
textField.backgroundColor = .green
return textField
}()
private lazy var testView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .systemPink
return view
}()
private lazy var button: UIButton = {
let view = UIButton()
view.backgroundColor = .blue
view.setTitle("hide it", for: .normal)
view.translatesAutoresizingMaskIntoConstraints = false
view.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
return view
}()
var heightConstraint: NSLayoutConstraint?
#objc func buttonTapped() {
heightConstraint?.isActive = false
heightConstraint = mytextFeild.heightAnchor.constraint(equalToConstant: 0)
heightConstraint?.isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mytextFeild)
view.addSubview(testView)
view.addSubview(button)
mytextFeild.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32).isActive = true
mytextFeild.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32.0).isActive = true
mytextFeild.topAnchor.constraint(equalTo: view.topAnchor, constant: 64).isActive = true
heightConstraint = mytextFeild.heightAnchor.constraint(equalToConstant: 32.0)
heightConstraint?.isActive = true
button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32.0).isActive = true
button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32.0).isActive = true
button.heightAnchor.constraint(equalToConstant: 32.0).isActive = true
button.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -64.0).isActive = true
testView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
testView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
testView.topAnchor.constraint(equalTo: mytextFeild.bottomAnchor).isActive = true
testView.bottomAnchor.constraint(equalTo: button.topAnchor).isActive = true
}
}
Add them to a stack then add stack to the viewController. at the end try to hide it easily without changing the height.
class ViewController: UIViewController {
private lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .center
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
private lazy var myTextField: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.text = "Hello world"
textField.backgroundColor = .green
return textField
}()
private lazy var testView: UIView = {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .systemPink
return view
}()
private lazy var button: UIButton = {
let view = UIButton()
view.backgroundColor = .blue
view.setTitle("hide it", for: .normal)
view.translatesAutoresizingMaskIntoConstraints = false
view.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
return view
}()
#objc func buttonTapped() {
myTextField.isHidden = !myTextField.isHidden
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
stackView.addArrangedSubview(myTextField)
stackView.addArrangedSubview(testView)
stackView.addArrangedSubview(button)
view.addSubview(stackView)
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -64.0).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
myTextField.heightAnchor.constraint(equalToConstant: 32.0).isActive = true
myTextField.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -64.0).isActive = true
testView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
button.heightAnchor.constraint(equalToConstant: 32.0).isActive = true
button.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -64.0).isActive = true
}
}

Can't Tap UIView in Nested ScrollView

I have a vertical UIScrollView, allScrollView, and a horizontal UIScrollView, hourlyScrollView, nested inside the vertical UIScrollView. In each of the scroll views I have 10 other UIViews that will show data. Each of the views are assigned a UITapGestureRecognizer. I'm able to tap the views that are only in the vertical scroll, but none of the views in the nested horizontal scroll do anything when tapped. If anyone can help me it would be greatly appreciated as I've tried a lot of suggestions on here with no luck.
my view hierarchy:
-allScrollView (vertical)
-allContentView
-hourlyScrollView (horizontal)
-hourlyContentView
-10 UIViews
-dailyContentView
-10 UIViews
viewDidLoad()
let dailyContentView = UIView()
let hourlyContentView = UIView()
let hourlyScrollView = UIScrollView()
let allContentView = UIView()
let allScrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
hourlyScrollView.translatesAutoresizingMaskIntoConstraints = false
hourlyContentView.translatesAutoresizingMaskIntoConstraints = false
allContentView.translatesAutoresizingMaskIntoConstraints = false
allScrollView.translatesAutoresizingMaskIntoConstraints = false
dailyContentView.translatesAutoresizingMaskIntoConstraints = false
layoutHourlyViews()
layoutDailyViews()
finishLayout()
}
create horizontal scroll content
func layoutHourlyViews() {
for subview in hourlyScrollView.subviews {
subview.removeFromSuperview()
}
for subView in hourlyContentView.subviews {
subView.removeFromSuperview()
}
var previousHour : UIView? = nil
for count in 1...10 {
let hourlyUIView = UIView()
hourlyUIView.backgroundColor = .blue
hourlyUIView.isUserInteractionEnabled = true
hourlyUIView.tag = count
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hourlyTap(_:)))
hourlyUIView.addGestureRecognizer(tapGesture)
let descriptionLabel = UILabel()
let borderView = UIView()
let borderViewTop = UIView()
let borderViewBottom = UIView()
borderViewTop.backgroundColor = .black
borderViewBottom.backgroundColor = .black
borderViewTop.translatesAutoresizingMaskIntoConstraints = false
borderViewBottom.translatesAutoresizingMaskIntoConstraints = false
borderView.translatesAutoresizingMaskIntoConstraints = false
hourlyUIView.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.text = "test"
borderView.backgroundColor = .black
hourlyUIView.addSubview(borderViewBottom)
hourlyUIView.addSubview(borderViewTop)
hourlyUIView.addSubview(descriptionLabel)
hourlyUIView.addSubview(borderView)
borderViewBottom.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
borderViewBottom.trailingAnchor.constraint(equalTo: hourlyUIView.trailingAnchor).isActive = true
borderViewBottom.bottomAnchor.constraint(equalTo: hourlyUIView.bottomAnchor).isActive = true
borderViewBottom.heightAnchor.constraint(equalToConstant: 2).isActive = true
borderViewTop.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
borderViewTop.trailingAnchor.constraint(equalTo: hourlyUIView.trailingAnchor).isActive = true
borderViewTop.topAnchor.constraint(equalTo: hourlyUIView.topAnchor).isActive = true
borderViewTop.heightAnchor.constraint(equalToConstant: 2).isActive = true
hourlyUIView.widthAnchor.constraint(equalToConstant: 160).isActive = true
hourlyUIView.heightAnchor.constraint(equalToConstant: 240).isActive = true
descriptionLabel.topAnchor.constraint(equalTo: hourlyUIView.topAnchor, constant: 16).isActive = true
descriptionLabel.centerXAnchor.constraint(equalTo: hourlyUIView.centerXAnchor, constant: 0).isActive = true
hourlyContentView.addSubview(hourlyUIView)
if previousHour == nil {
hourlyUIView.topAnchor.constraint(equalTo: hourlyContentView.topAnchor, constant: 0).isActive = true
hourlyUIView.leadingAnchor.constraint(equalTo: hourlyContentView.leadingAnchor, constant: 2).isActive = true
}
else {
hourlyUIView.topAnchor.constraint(equalTo: hourlyContentView.topAnchor, constant: 0).isActive = true
hourlyUIView.leadingAnchor.constraint(equalTo: previousHour!.trailingAnchor, constant: 0).isActive = true
borderView.bottomAnchor.constraint(equalTo: hourlyUIView.bottomAnchor).isActive = true
borderView.topAnchor.constraint(equalTo: hourlyUIView.topAnchor).isActive = true
borderView.widthAnchor.constraint(equalToConstant: 2).isActive = true
borderView.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
}
previousHour = hourlyUIView
}
let borderViewTop = UIView()
let borderViewBottom = UIView()
borderViewTop.backgroundColor = .black
borderViewBottom.backgroundColor = .black
borderViewTop.translatesAutoresizingMaskIntoConstraints = false
borderViewBottom.translatesAutoresizingMaskIntoConstraints = false
hourlyScrollView.addSubview(hourlyContentView)
hourlyContentView.leadingAnchor.constraint(equalTo: hourlyScrollView.leadingAnchor, constant: 0).isActive = true
hourlyContentView.topAnchor.constraint(equalTo: hourlyScrollView.topAnchor, constant: 0).isActive = true
hourlyContentView.trailingAnchor.constraint(equalTo: hourlyScrollView.trailingAnchor, constant: 0).isActive = true
hourlyContentView.bottomAnchor.constraint(equalTo: hourlyScrollView.bottomAnchor, constant: 0).isActive = true
allContentView.addSubview(hourlyScrollView)
hourlyScrollView.isScrollEnabled = true
hourlyScrollView.topAnchor.constraint(equalTo: allContentView.topAnchor, constant: 20).isActive = true
hourlyScrollView.leadingAnchor.constraint(equalTo: allContentView.leadingAnchor, constant: 0).isActive = true
hourlyScrollView.trailingAnchor.constraint(equalTo: allContentView.trailingAnchor, constant: 0).isActive = true
}
create vertical scroll content
func layoutDailyViews() {
for subview in dailyContentView.subviews {
subview.removeFromSuperview()
}
var previousDay : UIView? = nil
for count in 1...10 {
let dailyUIView = UIView()
//dailyUIView.isUserInteractionEnabled = true
dailyUIView.tag = count
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dailyTap(_:)))
dailyUIView.addGestureRecognizer(tapGesture)
//hourlyUIView.frame.size = CGSize(width: 500, height: 50)
let descriptionLabel = UILabel()
dailyUIView.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.text = "daily test"
let borderView = UIView()
borderView.translatesAutoresizingMaskIntoConstraints = false
borderView.backgroundColor = .black
dailyUIView.addSubview(descriptionLabel)
dailyUIView.addSubview(borderView)
borderView.bottomAnchor.constraint(equalTo: dailyUIView.bottomAnchor).isActive = true
borderView.heightAnchor.constraint(equalToConstant: 2).isActive = true
borderView.leadingAnchor.constraint(equalTo: dailyUIView.leadingAnchor).isActive = true
borderView.trailingAnchor.constraint(equalTo: dailyUIView.trailingAnchor).isActive = true
dailyUIView.heightAnchor.constraint(equalToConstant: 100).isActive = true
descriptionLabel.leadingAnchor.constraint(equalTo: dailyUIView.leadingAnchor, constant: 16).isActive = true
descriptionLabel.centerYAnchor.constraint(equalTo: dailyUIView.centerYAnchor, constant: 0).isActive = true
dailyContentView.addSubview(dailyUIView)
if previousDay == nil {
dailyUIView.topAnchor.constraint(equalTo: dailyContentView.topAnchor, constant: 0).isActive = true
}
else {
dailyUIView.topAnchor.constraint(equalTo: previousDay!.bottomAnchor, constant: 0).isActive = true
}
dailyUIView.widthAnchor.constraint(equalToConstant: view.frame.width - 4).isActive = true
dailyUIView.centerXAnchor.constraint(equalTo: dailyContentView.centerXAnchor).isActive = true
previousDay = dailyUIView
}
allContentView.addSubview(dailyContentView)
}
func finishLayout() {
hourlyScrollView.bottomAnchor.constraint(equalTo: dailyContentView.bottomAnchor, constant: 0).isActive = true
dailyContentView.topAnchor.constraint(equalTo: allContentView.topAnchor, constant: 260).isActive = true
dailyContentView.centerXAnchor.constraint(equalTo: allContentView.centerXAnchor, constant: 0).isActive = true
dailyContentView.leadingAnchor.constraint(equalTo: allContentView.leadingAnchor).isActive = true
dailyContentView.trailingAnchor.constraint(equalTo: allContentView.trailingAnchor, constant: 0).isActive = true
dailyContentView.bottomAnchor.constraint(equalTo: allContentView.bottomAnchor).isActive = true
allScrollView.addSubview(allContentView)
allContentView.topAnchor.constraint(equalTo: allScrollView.topAnchor).isActive = true
allContentView.leadingAnchor.constraint(equalTo: allScrollView.leadingAnchor).isActive = true
allContentView.trailingAnchor.constraint(equalTo: allScrollView.trailingAnchor).isActive = true
allContentView.bottomAnchor.constraint(equalTo: allScrollView.bottomAnchor).isActive = true
allContentView.centerXAnchor.constraint(equalTo: allScrollView.centerXAnchor).isActive = true
allContentView.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
allContentView.heightAnchor.constraint(equalToConstant: 1500).isActive = true
view.addSubview(allScrollView)
allScrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
allScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
allScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
allScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
tapped functions
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
hourlyScrollView.contentSize = CGSize(width:160 * 10 + 2, height:240)
allScrollView.contentSize = CGSize(width: view.frame.width, height:1500)
}
#objc func hourlyTap(_ sender: UITapGestureRecognizer) {
let tappedView = sender.view
print("hourly: \(tappedView!.tag)")
}
#objc func dailyTap(_ sender: UITapGestureRecognizer) {
let tappedView = sender.view
print("daily: \(tappedView!.tag)")
}
You haven't set all the required constraints on your hourlyContentView so the horizontal scrollView's size is (0,0) and as such it can't be scrolled or tapped. You can use Debug View Hierarchy in Xcode to see this.
The constraints you need to add are:
Between your last hourlyUIView's trailingAnchor and hourlyContentView's trailing anchor:
...
previousHour = hourlyUIView
}
previousHour?.trailingAnchor.constraint(equalTo: hourlyContentView.trailingAnchor).isActive = true
let borderViewTop = UIView()
let borderViewBottom = UIView()
...
Setting your hourlyContentView heightAnchor equal to the hourlyScrollView height anchor:
hourlyContentView.heightAnchor.constraint(equalTo: hourlyScrollView.heightAnchor).isActive = true

How can I show a hidden UIButton?

Views were placed using code.
If I press deleteButton (button), I want the hidden button(imgButton) to appear.
However, imgView's width is not refresh.
MainViewController.swift
import UIKit
class MainViewController: UIViewController {
var trashIsSelected: Bool!
let imgButton: UIButton = {
let imgView = UIButton()
imgView.setImage(UIImage(named: "schedule_delete_icon"), for: UIControlState.normal)
// imgView.imageView?.image = UIImage(named: "schedule_delete_icon")
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
let deleteButton: UIButton = {
let imgBtn = UIButton()
imgBtn.setImage(UIImage(named: "icon_delete"), for: UIControlState.normal)
// imgBtn.imageView?.image = UIImage(named: "icon_delete")
imgBtn.translatesAutoresizingMaskIntoConstraints = false
return imgBtn
}()
let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "하ㅣㅇ하이히아히아하하하하ㅏㅎ하ㅏㅎ하ㅏ하하하하ㅏㅏ하하하하하ㅏ"
return label
}()
var imgViewWidth: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
setupLayout()
}
func setupLayout(){
let testView = UIScrollView()
self.view.addSubview(testView)
testView.backgroundColor = .lightGray
testView.translatesAutoresizingMaskIntoConstraints = false
testView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
testView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
testView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
testView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.3).isActive = true
testView.addSubview(imgButton)
testView.addSubview(label)
imgButton.leadingAnchor.constraint(equalTo: testView.leadingAnchor, constant: 10).isActive = true
imgButton.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
imgButton.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
imgButton.widthAnchor.constraint(equalTo: imgButton.heightAnchor, multiplier: 0).isActive = true
imgButton.isHidden = true
trashIsSelected = false
label.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: imgButton.trailingAnchor, constant: 10).isActive = true
label.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
label.widthAnchor.constraint(equalTo: testView.widthAnchor, multiplier: 0.5).isActive = true
self.view.addSubview(deleteButton)
deleteButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
deleteButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
deleteButton.addTarget(self, action: #selector(self.addBtnAction(_:)), for: UIControlEvents.touchUpInside)
}
#objc func addBtnAction(_ sender: UIButton){
print("hi")
if trashIsSelected == false{
trashIsSelected = true
imgButton.isHidden = false
imgButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
imgButton.updateConstraints()
}else{
trashIsSelected = false
imgButton.widthAnchor.constraint(equalToConstant: 0).isActive = true
imgButton.isHidden = true
imgButton.updateConstraints()
}
}
}
This is error message:
2018-05-23 14:00:47.697959+0900 Test[67488:4887863] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"",
""
)
Will attempt to recover by breaking constraint
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.
You are adding new constraints to the button that conflict with the old ones (how can a button be 0 points wide, and simultaneously 50 points wide?). To make it work, you need to turn off the old constraint before you activate a new one. I recommend creating a property that would keep the current imgButton constraint at all times, and then when you want to change it, just use that (either turn it off and create a new one, or just set a constant, which in your case is better and easier):
import UIKit
class MainViewController: UIViewController {
// property referencing current imgButton width constraint
fileprivate var imgButtonWidthConstraint: NSLayoutConstraint!
var trashIsSelected: Bool!
let imgButton: UIButton = {
let imgView = UIButton()
imgView.setImage(UIImage(named: "schedule_delete_icon"), for: UIControlState.normal)
// imgView.imageView?.image = UIImage(named: "schedule_delete_icon")
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
let deleteButton: UIButton = {
let imgBtn = UIButton()
imgBtn.setImage(UIImage(named: "icon_delete"), for: UIControlState.normal)
// imgBtn.imageView?.image = UIImage(named: "icon_delete")
imgBtn.translatesAutoresizingMaskIntoConstraints = false
return imgBtn
}()
let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "하ㅣㅇ하이히아히아하하하하ㅏㅎ하ㅏㅎ하ㅏ하하하하ㅏㅏ하하하하하ㅏ"
return label
}()
var imgViewWidth: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
setupLayout()
}
func setupLayout(){
let testView = UIScrollView()
self.view.addSubview(testView)
testView.backgroundColor = .lightGray
testView.translatesAutoresizingMaskIntoConstraints = false
testView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
testView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
testView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
testView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.3).isActive = true
testView.addSubview(imgButton)
testView.addSubview(label)
imgButton.leadingAnchor.constraint(equalTo: testView.leadingAnchor, constant: 10).isActive = true
imgButton.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
imgButton.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
// keep the reference to constraint that defines width
// (we will use the constraint setting the width to constant, since then you can
// simply switch the constant between 0 and 50):
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalToConstant: 0)
imgButtonWidthConstraint.isActive = true
imgButton.isHidden = true
trashIsSelected = false
label.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: imgButton.trailingAnchor, constant: 10).isActive = true
label.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
label.widthAnchor.constraint(equalTo: testView.widthAnchor, multiplier: 0.5).isActive = true
self.view.addSubview(deleteButton)
deleteButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
deleteButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
deleteButton.addTarget(self, action: #selector(self.addBtnAction(_:)), for: UIControlEvents.touchUpInside)
}
#objc func addBtnAction(_ sender: UIButton){
print("hi")
if trashIsSelected == false{
trashIsSelected = true
imgButton.isHidden = false
// just change the constant to what you want
imgButtonWidthConstraint.constant = 50
imgButton.updateConstraints()
} else {
trashIsSelected = false
imgButtonWidthConstraint.constant = 0
imgButton.isHidden = true
imgButton.updateConstraints()
}
}
}
EDIT:
Just for completeness of the answer, if you were for some reason using constraints where changing a constant would not be enough, you would have to activate and deactivate the constraints. E.g., if you were using multiplier to determine imgButton's width, you would have to use this approach (multiplier is an immutable property of the NSLayoutConstraint). So therefore creating a constraint:
// simply switch the constant between 0 and 50):
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalTo: someOtherView.widthAnchor, multiplier: 0)
imgButtonWidthConstraint.isActive = true
And then in addBtnAction you would have to do to this:
#objc func addBtnAction(_ sender: UIButton){
print("hi")
if trashIsSelected == false{
trashIsSelected = true
imgButton.isHidden = false
// first deactivate current constraint
imgButtonWidthConstraint.isActive = false
// then create a new one and store it to imgButtonWidthConstraint property (the old one is deactivated, so you don't need a reference to it anymore)
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalTo: someOtherView.widthAnchor, multiplier: 0.75)
// and activate the new one
imgButtonWidthConstraint.isActive = true
imgButton.updateConstraints()
} else {
trashIsSelected = false
// same process again
imgButtonWidthConstraint.isActive = false
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalTo: someOtherView.widthAnchor, multiplier: 0)
imgButtonWidthConstraint.isActive = true
imgButton.isHidden = true
imgButton.updateConstraints()
}
}

Resources