0

I have a view structure like below;

-->Custom Scroll View
    -->Container View
       -->View
          -->Button

My problem is that I'm adding a target to UIButton but the touch function is not called. I tried to add the target both in custom view class or view controller. However, neither worked.

What I checked;

  • I checked if all views' isUserInteractionEnabled is set to true and all of them are true.
  • I also checked if button has a frame (some posts say about UIButton can be seen but you can't touch it because It has no frame).

I checked probably every answer in stack overflow and most of them talk about isUserInteraction and hierarchy and I think they are all correct in my situation.

UIButton not clickable when custom view called

Custom UIView add target not called

How I create custom view and add button inside of it.

class TyreChangeScrollView: UIScrollView {

//E-Mail
let emailTitleLbl = BaseLabel()
let emailBgView = UIView()
let emailLbl = BaseLabel()
public let emailInfoBtn = UIButton()

let contentView: UIView = {
    let v = UIView()
    v.translatesAutoresizingMaskIntoConstraints = false
    return v
}()

var shouldSetupConstraints = true

override init(frame: CGRect) {
    super.init(frame: frame)
    updateUI()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

func updateUI(){
    addSubview(contentView)

    emailTitleLbl.translatesAutoresizingMaskIntoConstraints = false
    emailTitleLbl.text =  "E-POSTA ADRESİ"
    emailTitleLbl.textAlignment = .left
    contentView.addSubview(emailTitleLbl)

    emailLbl.translatesAutoresizingMaskIntoConstraints = false
    emailLbl.text =  "hello@hello.com"
    emailLbl.textAlignment = .left
    emailInfoBtn.setImage(UIImage(named: "info"), for: .normal)
    emailInfoBtn.isUserInteractionEnabled = true
    emailBgView.backgroundColor = Color.Common.fieldBg
    emailBgView.addSubview(emailLbl)
    emailBgView.addSubview(emailInfoBtn)
    contentView.addSubview(emailBgView)
}
override func updateConstraints() {
    if(shouldSetupConstraints) {
        // AutoLayout constraints
        contentView.translatesAutoresizingMaskIntoConstraints = false
        // constrain the scroll view to 8-pts on each side
        contentView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
        contentView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1.0).isActive = true

        emailTitleLbl.anchor(phoneLbl.bottomAnchor, left: contentView.leftAnchor, bottom: nil, right: contentView.rightAnchor, topConstant: 10, leftConstant: 20, bottomConstant: 0, rightConstant: 16, widthConstant: 0, heightConstant: 0)
        emailLbl.anchor(emailBgView.topAnchor, left: emailBgView.leftAnchor, bottom: emailBgView.bottomAnchor, right: nil, topConstant: 0, leftConstant: 15, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
        emailInfoBtn.anchor(emailBgView.topAnchor, left: nil, bottom: emailBgView.bottomAnchor, right: emailBgView.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 10, widthConstant: 0, heightConstant: 0)
        emailBgView.anchor(emailTitleLbl.bottomAnchor, left: contentView.leftAnchor, bottom: nil, right: contentView.rightAnchor, topConstant: 10, leftConstant: 20, bottomConstant: 0, rightConstant: 16, widthConstant: 0, heightConstant: 50)

        shouldSetupConstraints = false
    }
    super.updateConstraints()
}
}

How I declare custom class and add target to UIButton.

class TyreChangeViewController: BaseViewController{

let scrollView = TyreChangeScrollView()

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    designUI()
    scrollView.emailInfoBtn.addTarget(self, action: #selector(emailBtnTapped(_:)), for: UIControlEvents.touchUpInside)
    scrollView.phoneInfoBtn.addTarget(self, action: #selector(phoneBtnTapped(_:)), for: UIControlEvents.touchUpInside)

}
override func viewWillAppear(_ animated: Bool) {

    scrollView.anchor(topLayoutGuide.bottomAnchor, left: view.leftAnchor, bottom: bottomLayoutGuide.topAnchor, right: view.rightAnchor, topConstant: 10, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 0)
}
func designUI(){

    view.backgroundColor = Color.Common.screenBgColor
    scrollView.backgroundColor = Color.Common.screenBgWhite
    view.addSubview(scrollView)

}
@objc func emailBtnTapped(_ sender: UIButton){
    print("hello")
}}

EDIT: If I add a height constraint to the content view, buttons are working but now it isn't scrollable.

contentView.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 1.0).isActive = true
Emre Önder
  • 2,408
  • 2
  • 23
  • 73
  • What does the view-hierchy tells you about scroll view size? – Vollan Apr 05 '18 at 11:15
  • It says "Scrollable content size is ambiguous for TyreChangeScrollView" but has height of 534 in Debug View Hiearchy – Emre Önder Apr 05 '18 at 11:17
  • My guess is that the height constant of 0 conflicts with your bottom and height constraint to it. Make the scrollview go to edges and your containerView go height and width to `UIScreen.main.bounds.height / width` and center x,y in scrollView – Vollan Apr 05 '18 at 11:23
  • I edit my question. can you please check it? – Emre Önder Apr 05 '18 at 11:24
  • Your scrollview is 0 width i think, so set your contentView width as well – Vollan Apr 05 '18 at 11:28
  • Hmmm but when I equal width and height of content view to scrollview, It is working. I think It won't If were 0. What do u think? – Emre Önder Apr 05 '18 at 11:30
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/168299/discussion-between-vollan-and-emre-onder). – Vollan Apr 05 '18 at 11:31

1 Answers1

1

After adding a constraint refreshing layout is a must

override func viewWillAppear(_ animated: Bool) {

    scrollView.anchor(topLayoutGuide.bottomAnchor, left: view.leftAnchor, bottom: bottomLayoutGuide.topAnchor, right: view.rightAnchor, topConstant: 10, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 0)

    self.view.layoutIfNeeded()
 }
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • I add a big label below that emailView to check If It is scrollable. I make that labels below constraint to self.contenview.belowanchor but make it not scrollable. – Emre Önder Apr 05 '18 at 11:29
  • in viewWillAppear add self.view.layoutIfNeeded() – Shehata Gamal Apr 05 '18 at 11:32
  • 1
    You are the MAN! Thank you :) It worked. Can you please edit your answer and I'll tick as working sol. – Emre Önder Apr 05 '18 at 11:34
  • Can I ask something more? In most of posts, they say I need to have both equal Width and Height but I just assign width in my code because when I make height constraint equal with scrollview, It won't scroll. It will be a problem? – Emre Önder Apr 05 '18 at 11:38
  • contentView of the scrollView must get it's width from outside the scrollView to a static width or width related to any outer component , but height (of contentView) must be calculated dynamically from inner items by correctly hooking them all from top to bottom of contentView , so auto-layout can calculate it's proper height and the scrollView can scroll accordingly – Shehata Gamal Apr 05 '18 at 11:43
  • So assign width anchor of content view to scrollview.widthanchor is correct? – Emre Önder Apr 05 '18 at 11:44
  • no , it's not rigth as the scrollView finds it's size from inner item by being connceted properly from top to bottom fro vertical , leading to trailing fro horizental – Shehata Gamal Apr 05 '18 at 12:15