Search code examples
swiftuitableviewuiviewuikituitapgesturerecognizer

Handling a tap of UIImage inside of UITableViewHeaderFooterView


I have a custom UITableViewHeaderFooterView which is called ProfileHeaderView. It does contain UIImageView called userImage. How can I access this userImage for adding a tap gesture. Here's the piece of code for my header:

class ProfileHeaderView: UITableViewHeaderFooterView {
    
    // MARK: - Subviews
    
    private var statusText: String = ""
    
    lazy var userImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: me.login))
                
        imageView.layer.cornerRadius = 45
        imageView.clipsToBounds = true
                
        imageView.translatesAutoresizingMaskIntoConstraints = false
        
        imageView.isUserInteractionEnabled = true
        
        return imageView
    }()
...
}

And here's the code I'm using inside a UIViewController:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        if section == 0 {
            let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: "ProfileHeaderView")
            view?.isUserInteractionEnabled = true
            
            
            let tapPicture = UITapGestureRecognizer(
                target: self,
                action: #selector(didTapPicture)
            )
            
            tapPicture = 1
            view?.userImage.addGestureRecognizer(tapPicture)
            return view
        }
        return nil
    }

I do get the following error: Value of type 'UITableViewHeaderFooterView' has no member 'userImage'. Why? I was thinking I added userImage to my header. But turns out adding it to my custom header is not enough. Is there any workaround or solution to add tapGesture to it?


Solution

  • dequeueReusableHeaderFooterView returns UITableViewHeaderFooterView which does not have a userImage property, hence the error.

    All you need is to cast the result of dequeueReusableHeaderFooterView to ProfileHeaderView.

    if let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: "ProfileHeaderView") as? ProfileHeaderView {
        view.isUserInteractionEnabled = true
        
        let tapPicture = UITapGestureRecognizer(
            target: self,
            action: #selector(didTapPicture)
        )
        
        tapPicture = 1
        view.userImage.addGestureRecognizer(tapPicture)
        return view
    }
    

    One issue with this is that you will end up adding more and more gesture recognizers to the header as the user scrolls.

    A better overall solution is to setup the gesture in the custom header class and define either a delegate or a callback property. Then when the custom header handles the tap, it can call the delegate or callback so the view controller can act as needed.