Mask UIView with another UIView - ios

Yes this question has been asked before, the solutions did not work or had different applications.
It is the most basic setup. I have two rectangular UIViews, red and blue.
I would like the blue square to cut into the red square, so the red square looks like an "L"
import Foundation
import UIKit
class TestController: UIViewController {
override func viewDidLoad() {
view.backgroundColor = .gray
view.addSubview(viewA)
view.addSubview(maskView)
viewA.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
viewA.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
viewA.widthAnchor.constraint(equalToConstant: 100).isActive = true
viewA.heightAnchor.constraint(equalToConstant: 100).isActive = true
viewA.translatesAutoresizingMaskIntoConstraints = false
maskView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 50).isActive = true
maskView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50).isActive = true
maskView.widthAnchor.constraint(equalToConstant: 100).isActive = true
maskView.heightAnchor.constraint(equalToConstant: 100).isActive = true
maskView.translatesAutoresizingMaskIntoConstraints = false
// Things which don't work
//viewA.mask = maskView // both views disappear
//viewA.layer.mask = maskView.layer // both views disappear
//viewA.layer.addSublayer(maskView.layer) // hides mask view
}
var viewA: UIView = {
let view = UIView()
view.backgroundColor = .red
view.layer.masksToBounds = true
return view
}()
var maskView: UIView = {
let view = UIView()
view.backgroundColor = .blue
return view
}()
}
This is the result I am expecting: (done in Photoshop)

As there is no magic way to mask the way in iOS, I present here a simple way to achieve this.
Don't forget to pan the clear area, If leaving the red square, it will become a blue square.
It's not hard to modify the subclass of UIViews for your own purpose, especially views.
import UIKit
class TestController: UIViewController {
override func viewDidLoad() {
view.backgroundColor = .gray
view.addSubview(viewA)
view.addSubview(maskView)
maskView.maskedView = viewA
viewA.activeMask = maskView
viewA.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
viewA.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
viewA.widthAnchor.constraint(equalToConstant: 100).isActive = true
viewA.heightAnchor.constraint(equalToConstant: 100).isActive = true
viewA.translatesAutoresizingMaskIntoConstraints = false
maskView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 50).isActive = true
maskView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50).isActive = true
maskView.widthAnchor.constraint(equalToConstant: 100).isActive = true
maskView.heightAnchor.constraint(equalToConstant: 100).isActive = true
maskView.translatesAutoresizingMaskIntoConstraints = false
}
var viewA: MyUIView = {
let view = MyUIView()
view.backgroundColor = .clear
view.layer.masksToBounds = true
return view
}()
var maskView: ActiveMaskView = {
let view = ActiveMaskView()
view.backgroundColor = .clear
return view
}()
}
class ActiveMaskView: UIView{
override func didMoveToSuperview() {
super.didMoveToSuperview()
let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(moveAround(_:)))
self.addGestureRecognizer(panGesture)
}
weak var maskedView : UIView?
private var frameOrigin : CGPoint = CGPoint.zero
#objc func moveAround(_ panGesture: UIPanGestureRecognizer){
guard let superview = superview else {return}
switch panGesture.state {
case .began:
frameOrigin = frame.origin
self.backgroundColor = UIColor.blue
case .changed:
let translation = panGesture.translation(in: superview)
frame = CGRect.init(origin: CGPoint.init(x: frameOrigin.x + translation.x, y: frameOrigin.y + translation.y), size: frame.size)
maskedView?.setNeedsDisplay()
break
case .ended:
self.backgroundColor =
frame.intersects(maskedView!.frame) ?
UIColor.clear : UIColor.blue
maskedView?.setNeedsDisplay()
case .cancelled:
frame = CGRect.init(origin: frameOrigin , size: frame.size)
self.backgroundColor =
frame.intersects(maskedView!.frame) ?
UIColor.clear : UIColor.blue
maskedView?.setNeedsDisplay()
default:
break;
}
}
}
class MyUIView: UIView{
weak var activeMask: ActiveMaskView?
override func draw(_ rect: CGRect) {
super.draw(rect)
let ctx = UIGraphicsGetCurrentContext()
ctx?.setFillColor(UIColor.red.cgColor)
ctx?.fill(self.layer.bounds)
ctx?.setBlendMode(.sourceOut)
guard let activeMask = activeMask , let superview = superview else {
return
}
let sc = frame.intersection(activeMask.frame)
let interSection = superview.convert(sc, to: self)
ctx?.fill(interSection )
}
}

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.

TapGestureRecognizer not working in UIView subviews

I want to add a tap gesture recognizer to a custom UIView (which represent an Image and a Label). It seems that the gesture recognizer is not added to the view or that the subviews are not considered as the UIView itself, hence not working.
Here is how I add my view :
Navbar.swift :
let indexSubview = IconTextView(svgName: "https://placeholder.pics/svg/30", textKey: "Index")
self.indexButton.addSubview(indexSubview)
let indexButtonTap = UITapGestureRecognizer(target: self, action: #selector(goToIndex))
indexButton.addGestureRecognizer(indexButtonTap)
(IconTextView being my custom view)
Then when I tap the indexButtonnothing is working.
My tap function, just in case:
#objc func goToIndex(sender:UITapGestureRecognizer) {
print("GO TO INDEX")
router.setRoute(routeName: "INDEX", routeParam: "")
}
I don't understand why it is not working, the userInteractions are enabled on all the elements.
Your precedent code + tap gesture, I edit constraints, add containerView:
class Aiutotipo: UIViewController {
let myImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleToFill
iv.clipsToBounds = true
iv.backgroundColor = .red
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
let myLabel: UILabel = {
let label = UILabel()
label.text = "Débats"
label.textColor = .white
label.textAlignment = .center
label.font = .systemFont(ofSize: 30, weight: .semibold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let containerView = UIView() //your container view
override func viewDidLoad() {
super.viewDidLoad()
containerView.backgroundColor = .red // red bacground for container view visible, set .clear for transparent bg
containerView.isUserInteractionEnabled = true
containerView.translatesAutoresizingMaskIntoConstraints = false
let indexButtonTap = UITapGestureRecognizer(target: self, action: #selector(goToIndex))
containerView.addGestureRecognizer(indexButtonTap)
myImageView.image = UIImage(named: "profilo") // set here your image
let myWidth = myLabel.intrinsicContentSize.width // This reveal only text width in label
view.addSubview(containerView)
containerView.heightAnchor.constraint(equalToConstant: myWidth + 50).isActive = true
containerView.widthAnchor.constraint(equalToConstant: myWidth).isActive = true
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
containerView.addSubview(myImageView)
myImageView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
myImageView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
myImageView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
myImageView.heightAnchor.constraint(equalTo: myImageView.widthAnchor).isActive = true
containerView.addSubview(myLabel)
myLabel.topAnchor.constraint(equalTo: myImageView.bottomAnchor).isActive = true
myLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
myLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
myLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
}
#objc fileprivate func goToIndex() {
print("GO TO INDEX")
}
}
This is the result

Trying to programmatically add UIScrollView to my App and I keep getting a blank View

Trying to create a UIScrollView and I cant seem to get my labels to appear as I would like them dead center.
lazy var label : UILabel = {
let label = UILabel()
label.text = "center of container view.center of container view"
label.font = UIFont(name: "Bebas Neue", size: 23)!
label.textColor = .black
return label
}()
// Mark: Properties
lazy var contentViewSize = CGSize(width: self.view.frame.width + 1200, height: self.view.frame.height)
// Mark: Views
fileprivate lazy var parentScrollView : UIView = {
var newView = UIView()
newView.translatesAutoresizingMaskIntoConstraints = false
newView.backgroundColor = .black
newView.frame = self.scrollView.bounds
newView.frame.size = contentViewSize
return newView
}()
fileprivate lazy var scrollView : UIScrollView = {
var uiScrollView = UIScrollView(frame: .zero)
uiScrollView.translatesAutoresizingMaskIntoConstraints = false
uiScrollView.frame = view.bounds
uiScrollView.backgroundColor = .gray
uiScrollView.addViewBorder(borderColor: UIColor.gray.cgColor, borderWith: 10, borderCornerRadius: 0)
// uiScrollView.alpha =
uiScrollView.contentSize = contentViewSize
// uiScrollView.autoresizingMask = .flexibleHeight
uiScrollView.showsVerticalScrollIndicator = true
uiScrollView.bounces = true
return uiScrollView
}()
fileprivate lazy var tutorialView : UIStackView = {
var tutView = UIStackView(arrangedSubviews: [label,label,label])
tutView.axis = .horizontal
tutView.backgroundColor = .white
tutView.distribution = .fillEqually
tutView.spacing = 0
return tutView
}()
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(parentScrollView)
parentScrollView.addSubview(tutorialView)
scrollView.widthAnchor.constraint(equalTo:self.view.widthAnchor,multiplier: 0.9).isActive = true
scrollView.heightAnchor.constraint(equalTo:self.view.heightAnchor,multiplier: 0.7).isActive = true
scrollView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 75).isActive = true
tutorialView.topAnchor.constraint(equalTo: parentScrollView.topAnchor,constant: +10).isActive = true}
It seems that when I add that last constraight with the topAnchor I get a blank screen. When I take that off I actually get the borders between the two views and I am able to do some scrolling.
Any help would be appreciated. Thank you
Did you give a value to the scrollView?
uiScrollView.contentSize.width = 1200
Then give the tutorialView the same width constraint with the other constraints.
NSLayoutConstraint.activate([
tutorialView.widthAnchor.constraint(equalToConstant: 1200),
tutorialView.heightAnchor.constraint(equalTo: uiScrollView.heightAnchor)
])
You have to add tutView.translatesAutoresizingMaskIntoConstraints = false when giving layout constraints in closure of tutorialView and also there are some mistakes in your code. So included some changes in your code and check updated code:
lazy var label : UILabel = {
let label = UILabel()
label.text = "center of container view.center of container view"
label.font = UIFont(name: "Bebas Neue", size: 23)!
label.textColor = .green
return label
}()
// Mark: Properties
lazy var contentViewSize = CGSize(width: self.view.frame.width + 1200, height: self.view.frame.height)
// Mark: Views
fileprivate lazy var parentScrollView : UIView = {
var newView = UIView()
newView.translatesAutoresizingMaskIntoConstraints = false
newView.backgroundColor = UIColor.clear
// newView.layer.borderWidth = 2
// newView.layer.borderColor = UIColor.yellow.cgColor
return newView
}()
fileprivate lazy var scrollView : UIScrollView = {
var uiScrollView = UIScrollView()
uiScrollView.translatesAutoresizingMaskIntoConstraints = false
// uiScrollView.frame = view.bounds
uiScrollView.backgroundColor = .orange
uiScrollView.layer.borderColor = UIColor.blue.cgColor
uiScrollView.layer.borderWidth = 2
uiScrollView.layer.cornerRadius = 0
// uiScrollView.alpha =
uiScrollView.contentSize = contentViewSize
// uiScrollView.autoresizingMask = .flexibleHeight
uiScrollView.showsVerticalScrollIndicator = true
uiScrollView.bounces = true
return uiScrollView
}()
fileprivate lazy var tutorialView : UIStackView = {
var tutView = UIStackView(arrangedSubviews: [label,label,label])
tutView.axis = .horizontal
tutView.backgroundColor = .red
tutView.distribution = .fill
tutView.translatesAutoresizingMaskIntoConstraints = false
return tutView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(parentScrollView)
parentScrollView.addSubview(tutorialView)
scrollView.widthAnchor.constraint(equalTo:self.view.widthAnchor,multiplier: 0.9).isActive = true
scrollView.heightAnchor.constraint(equalTo:self.view.heightAnchor,multiplier: 0.7).isActive = true
scrollView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 25).isActive = true
parentScrollView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
parentScrollView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10).isActive = true
parentScrollView.heightAnchor.constraint(equalToConstant: 200).isActive = true
parentScrollView.widthAnchor.constraint(equalToConstant: 200).isActive = true
// scrollView.layer.borderWidth = 2
// scrollView.layer.borderColor = UIColor.blue.cgColor
tutorialView.heightAnchor.constraint(equalTo: parentScrollView.heightAnchor).isActive = true
tutorialView.widthAnchor.constraint(equalToConstant: 1200).isActive = true
}

UIButton in a view with animation not detecting touch

I'm following a tutorial to create an interactive popup animation (http://www.swiftkickmobile.com/building-better-app-animations-swift-uiviewpropertyanimator/), and now would like to add buttons to the popup rather than have static text as in the tutorial.
The animation works fine, but the buttons are not detecting touch. Touching the button causes the animation to reverse, instead of printing my "test" statement.
From research, it looks to either be an issue with view hierarchies, the animation disabling the button touch, or layout/constraint issues with the button. I've tried addressing the above issues, but nothing has worked, was hoping someone might be able to help?
I've left out the code pertaining to the animation since I think the issue is to do with layout (and the animation seems to be working fine) - but it's still a lot; apologies in advance for the large amount of code.
class ViewController: UIViewController {
private let popupOffset: CGFloat = 440
private lazy var contentImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "Background")
return imageView
}()
private lazy var overlayView: UIView = {
let view = UIView()
view.backgroundColor = .black
view.alpha = 0
return view
}()
private lazy var popupView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.1
view.layer.shadowRadius = 10
return view
}()
private lazy var closedTitleLabel: UILabel = {
let label = UILabel()
label.text = "Hello"
label.font = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.medium)
label.textColor = UIColor.darkGray
label.textAlignment = .center
return label
}()
private lazy var openTitleLabel: UILabel = {
let label = UILabel()
label.text = "Which door will you choose?"
label.font = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.medium)
label.textColor = UIColor.darkGray
label.textAlignment = .center
label.alpha = 0
label.transform = CGAffineTransform(scaleX: 1.6, y: 1.6).concatenating(CGAffineTransform(translationX: 0, y: 15))
return label
}()
private lazy var reviewsImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "LabelBackground")
return imageView
}()
let stackView = UIStackView()
let buttonA = UIButton()
let buttonB = UIButton()
let buttonC = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
layout()
popupView.addGestureRecognizer(panRecognizer)
}
override var prefersStatusBarHidden: Bool {
return true
}
//Layout
private var bottomConstraint = NSLayoutConstraint()
private func layout() {
contentImageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(contentImageView)
contentImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
contentImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
contentImageView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
contentImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
overlayView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(overlayView)
overlayView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
overlayView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
overlayView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
overlayView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
popupView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(popupView)
popupView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
popupView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
bottomConstraint = popupView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: popupOffset)
bottomConstraint.isActive = true
popupView.heightAnchor.constraint(equalToConstant: 500).isActive = true
closedTitleLabel.translatesAutoresizingMaskIntoConstraints = false
popupView.addSubview(closedTitleLabel)
closedTitleLabel.leadingAnchor.constraint(equalTo: popupView.leadingAnchor).isActive = true
closedTitleLabel.trailingAnchor.constraint(equalTo: popupView.trailingAnchor).isActive = true
closedTitleLabel.topAnchor.constraint(equalTo: popupView.topAnchor, constant: 20).isActive = true
openTitleLabel.translatesAutoresizingMaskIntoConstraints = false
popupView.addSubview(openTitleLabel)
openTitleLabel.leadingAnchor.constraint(equalTo: popupView.leadingAnchor).isActive = true
openTitleLabel.trailingAnchor.constraint(equalTo: popupView.trailingAnchor).isActive = true
openTitleLabel.topAnchor.constraint(equalTo: popupView.topAnchor, constant: 20).isActive = true
reviewsImageView.translatesAutoresizingMaskIntoConstraints = false
popupView.addSubview(reviewsImageView)
reviewsImageView.leadingAnchor.constraint(equalTo: popupView.leadingAnchor).isActive = true
reviewsImageView.trailingAnchor.constraint(equalTo: popupView.trailingAnchor).isActive = true
reviewsImageView.bottomAnchor.constraint(equalTo: popupView.bottomAnchor).isActive = true
reviewsImageView.heightAnchor.constraint(equalToConstant: 428).isActive = true
buttonA.backgroundColor = UIColor.clear
let heightConstraintA = buttonA.heightAnchor.constraint(equalToConstant: 135)
heightConstraintA.isActive = true
heightConstraintA.priority = UILayoutPriority(rawValue: 999)
buttonA.translatesAutoresizingMaskIntoConstraints = false
buttonA.setTitle("A", for: .normal)
buttonA.setTitleColor(UIColor.darkGray, for: .normal)
buttonA.backgroundColor = UIColor.clear
buttonA.addTarget(self, action: #selector(buttonATapped(sender:)), for: .touchDown)
//self.popupView.addSubview(buttonA)
buttonB.backgroundColor = UIColor.clear
let heightConstraintB = buttonB.heightAnchor.constraint(equalToConstant: 135)
heightConstraintB.isActive = true
heightConstraintB.priority = UILayoutPriority(rawValue: 999)
buttonB.translatesAutoresizingMaskIntoConstraints = false
buttonB.setTitle("B", for: .normal)
buttonB.setTitleColor(UIColor.darkGray, for: .normal)
buttonB.backgroundColor = UIColor.clear
//self.popupView.addSubview(buttonB)
buttonC.backgroundColor = UIColor.clear
let heightConstraintC = buttonC.heightAnchor.constraint(equalToConstant: 135)
heightConstraintC.isActive = true
heightConstraintC.priority = UILayoutPriority(rawValue: 999)
buttonC.translatesAutoresizingMaskIntoConstraints = false
buttonC.setTitle("C", for: .normal)
buttonC.setTitleColor(UIColor.darkGray, for: .normal)
buttonC.backgroundColor = UIColor.clear
//self.popupView.addSubview(buttonC)
popupView.addSubview(stackView)
stackView.backgroundColor = UIColor.clear
stackView.addArrangedSubview(buttonA)
stackView.addArrangedSubview(buttonB)
stackView.addArrangedSubview(buttonC)
stackView.translatesAutoresizingMaskIntoConstraints = false
popupView.addSubview(stackView)
stackView.leadingAnchor.constraint(equalTo: popupView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: popupView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: popupView.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 428).isActive = true
stackView.axis = .vertical
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
}
#objc func buttonATapped(sender: UIButton) {
print ("test")
}
private func animateTransitionIfNeeded(to state: State, duration: TimeInterval) {
//Animation code
}
#objc private func popupViewPanned(recognizer: UIPanGestureRecognizer) {
//Animation code
}
}
***For anyone else having the same issue, here is how I solved it, thanks to #OverD:
I removed the reviewsImageView completely (because that was only for color in my case, and I can easily add the color to the UIButton instead) Then instead of adding the buttons to the popupView, I added them to the stack view, and the stack view to the popupView. Lastly, my syntax for addTarget was not correct, and for some reason changing it to touchDown instead of touchUpInside made it work.
I noticed from the provided code that you are adding the same buttons multiple times, once as a subview of the popView and once in the stackView. Also you are not assigning any targets for the buttons.
I hope this helps

Add imageview to a scrollview page control

My code below is a basic scrollview using page control which uses basic colors on each screen. I want to display an imageview over the uiview which displays the basic colors. I want to call var pics from the asset file in Xcode.
var colors:[UIColor] = [UIColor.red, UIColor.blue, UIColor.green, UIColor.yellow]
var pics = ["a","b","c","d"]
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(scrollView)
for index in 0..<4 {
frame.origin.x = self.scrollView.frame.size.width * CGFloat(index)
frame.size = self.scrollView.frame.size
let subView = UIView(frame: frame)
subView.backgroundColor = colors[index]
self.scrollView .addSubview(subView)
}
func configurePageControl() {
self.pageControl.numberOfPages = colors.count
}
Here I suppose that you have 4 images attached in your project named 0,1,2,3 png , try this
import UIKit
class ViewController: UIViewController , UIScrollViewDelegate {
let scrollView = UIScrollView()
let pageCon = UIPageControl()
override func viewDidLoad() {
super.viewDidLoad()
let viewsCount = 4
var prevView = self.view!
scrollView.delegate = self
scrollView.isPagingEnabled = true
pageCon.numberOfPages = viewsCount
pageCon.currentPage = 0
pageCon.tintColor = .green
pageCon.currentPageIndicatorTintColor = .orange
pageCon.backgroundColor = .blue
pageCon.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
view.insertSubview(pageCon, aboveSubview: scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant:20),
scrollView.heightAnchor.constraint(equalToConstant: 400),
pageCon.centerXAnchor.constraint(equalTo: view.centerXAnchor),
pageCon.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant:-20),
])
for i in 0..<viewsCount {
let imageV = UIImageView()
imageV.image = UIImage(named: "\(i).png")
imageV.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(imageV)
if prevView == self.view {
imageV.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
}
else {
imageV.leadingAnchor.constraint(equalTo: prevView.trailingAnchor).isActive = true
}
NSLayoutConstraint.activate([
imageV.topAnchor.constraint(equalTo: scrollView.topAnchor),
imageV.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
imageV.widthAnchor.constraint(equalToConstant: self.view.frame.width),
imageV.heightAnchor.constraint(equalToConstant: 400)
])
if i == viewsCount - 1 {
imageV.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
}
prevView = imageV
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
pageCon.currentPage = Int(scrollView.contentOffset.x / self.view.frame.width)
}
}

Resources