Torkil Vatne
Torkil Vatne

Reputation: 97

Swift - Header in UITableView blocks button interaction

In my UITableView I want to have an option to click a button which have a fixed posision (see attached picture). But anything that is in front or behind the UITableView's section headers is blocked from interaction, it does not register the button taps. I've tried to set a higher zPosition, which brings the buttons in front of the headers, but I still can't press the buttons. This is what it lookes like:

Image that shows the buttons before and after (nameOfButton).layer.zPosition = 99 is applied.

Even though my buttons is in front of the headers, the button taps is not registered...

I'm creating the buttons programatically, and my viewDidLoad lookes like this:

override func viewDidLoad() {
        super.viewDidLoad()

        // Allow iOS to resize the cells automatically according to our Auto Layout constraints
        tableView.rowHeight = UITableViewAutomaticDimension

        // We will take ownership of the header view we've so nicely setup in the storyboard and then remove it from the table view.
        headerView = tableView.tableHeaderView
        tableView.tableHeaderView = nil
        tableView.addSubview(headerView)
        let addPhotoTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.addPhoto(_:)))
        headerView.addGestureRecognizer(addPhotoTapGesture)

        // PhotoPicker
        createPhotoPickerButtons()

        let effectiveHeight = kTableHeaderHeight-kTableHeaderCutAway/2
        tableView.contentInset = UIEdgeInsets(top: effectiveHeight, left: 0, bottom: 0, right: 0)
        tableView.contentOffset = CGPoint(x: 0, y: -effectiveHeight)

        headerMaskLayer = CAShapeLayer()
        headerMaskLayer.fillColor = UIColor.blackColor().CGColor

        headerView.layer.mask = headerMaskLayer
        updateHeaderView()
    } 

And my createPhotoPickerButtons() (Here I'm placing the buttons below the view so I can animate their appearance with showImagePicker():

func createPhotoPickerButtons() {

        takePhotoButton = UIButton.init(type: UIButtonType.System) // .System
        photoLibraryButton = UIButton.init(type: UIButtonType.System) // .System
        cancelButton = UIButton.init(type: UIButtonType.System) // .System

        takePhotoButton.frame = CGRectMake(20, (0 + self.tableView.contentOffset.y + UIScreen.mainScreen().bounds.height), (UIScreen.mainScreen().bounds.width - 40), 40)
        photoLibraryButton.frame = CGRectMake(20, (0 + self.tableView.contentOffset.y + UIScreen.mainScreen().bounds.height), (UIScreen.mainScreen().bounds.width - 40), 40)
        cancelButton.frame = CGRectMake(20, (0 + self.tableView.contentOffset.y + UIScreen.mainScreen().bounds.height), (UIScreen.mainScreen().bounds.width - 40), 40)

        takePhotoButton.backgroundColor = UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0)
        photoLibraryButton.backgroundColor = UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0)
        cancelButton.backgroundColor = UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0)

        takePhotoButton.setTitle("Take Photo", forState: UIControlState.Normal)
        photoLibraryButton.setTitle("Photo Library", forState: UIControlState.Normal)
        cancelButton.setTitle("Cancel", forState: UIControlState.Normal)

        takePhotoButton.titleLabel?.font = UIFont.systemFontOfSize(17)
        photoLibraryButton.titleLabel?.font = UIFont.systemFontOfSize(17)
        cancelButton.titleLabel?.font = UIFont.systemFontOfSize(17)

        takePhotoButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
        photoLibraryButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
        cancelButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)

        let takePhotoButtonTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.takePhotoButtonAction(_:)))
        takePhotoButton.addGestureRecognizer(takePhotoButtonTapGesture)
        let photoLibraryButtonTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.photoLibraryButtonAction(_:)))
        photoLibraryButton.addGestureRecognizer(photoLibraryButtonTapGesture)
        let cancelButtonTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.cancelButtonAction(_:)))
        cancelButton.addGestureRecognizer(cancelButtonTapGesture)

        self.tableView.addSubview(takePhotoButton)
        self.tableView.addSubview(photoLibraryButton)
        self.tableView.addSubview(cancelButton)

        takePhotoButton.layer.zPosition = 99
        photoLibraryButton.layer.zPosition = 99
        cancelButton.layer.zPosition = 99

        takePhotoButton.alpha = 0
        photoLibraryButton.alpha = 0
        cancelButton.alpha = 0

    }

And at last my showImagePicker()which is called in addPhoto() (the action that is called when the user taps the image):

func showImagePicker(){

        // (0 + self.tableView.contentOffset.y + UIScreen.mainScreen().bounds.height - 50 - 10 - 50 - 10 - 50 - 10)

        UIView.animateWithDuration(0.5) {
            self.takePhotoButton.alpha = 1
            self.photoLibraryButton.alpha = 1
            self.cancelButton.alpha = 1

            self.takePhotoButton.frame.origin.y = 0 + self.tableView.contentOffset.y + UIScreen.mainScreen().bounds.height - 50 - 10 - 50 - 10 - 50 - 10
            self.photoLibraryButton.frame.origin.y = 0 + self.tableView.contentOffset.y + UIScreen.mainScreen().bounds.height - 50 - 10 - 50 - 10
            self.cancelButton.frame.origin.y = 0 + self.tableView.contentOffset.y + UIScreen.mainScreen().bounds.height - 50 - 10
        }
    }

I can't find anything about this on SO, and don't know of another solution for the buttons in the tableView.

Upvotes: 4

Views: 2445

Answers (3)

Adam Smaka
Adam Smaka

Reputation: 6393

it took me a while to find solution but i figure it out:

sectionView.userInteractionEnabled = false

+

sectionView.layer.zPosition = -1

EDIT: SWIFT 3 UPDATE:

view.isUserInteractionEnabled = false

Upvotes: 4

Varun
Varun

Reputation: 759

First your code has issues.

Never add tap gestures to UIButton.

Instead, try addTarget(target: AnyObject?, action: Selector, forControlEvents controlEvents: UIControlEvents). This is used for handling tap on button.

Upvotes: 0

Olivier Wilkinson
Olivier Wilkinson

Reputation: 2856

Your problem is that you are declaring your gesture recognisers inside a function, if you do this then they will be destroyed after the function body finishes.

Declare your recognisers outside of createPhotoPickerButtons. So above viewDidLoad:

var takePhotoButtonTapGesture: UITapGestureRecognizer!
var photoLibraryButtonTapGesture: UITapGestureRecogniser!
var cancelButtonTapGesture: UITapGestureRecogniser!

And in createPhotoPickerButtons:

func createPhotoPickerButtons() {

    takePhotoButtonTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.takePhotoButtonAction(_:)))
    takePhotoButton.addGestureRecognizer(takePhotoButtonTapGesture)
    photoLibraryButtonTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.photoLibraryButtonAction(_:)))
    photoLibraryButton.addGestureRecognizer(photoLibraryButtonTapGesture)
    cancelButtonTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.cancelButtonAction(_:)))
    cancelButton.addGestureRecognizer(cancelButtonTapGesture)

}

Upvotes: 1

Related Questions