Home > OS >  How to add UIView Gesture - Programmatically UIView
How to add UIView Gesture - Programmatically UIView

Time:08-15

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.

enter image description here

CodePudding user response:

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":

enter image description here

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:

enter image description here

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:

enter image description here

Now, because the views have a size, the Tap Gestures will work.

  • Related