4

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.

3 Answers3

4

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
Adam Smaka
  • 5,977
  • 3
  • 50
  • 55
1

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)

}
Olivier Wilkinson
  • 2,836
  • 15
  • 17
  • Gestures are a subclass of NSObject. So they won't be destroyed until the view, to which it is added, is removed. – Varun Apr 16 '16 at 12:14
  • Hi, thanks for the suggestion, but unfortunately it does not work... I've tried Varun's suggestion, but that does not work either. The buttons does not respond when they are in front of a section header. The buttons that are not in front works. Here's a picture showing that the "Photo Library"-button works, but not the "Take Photo"-button (because the header is behind): [Image of the problem](http://postimg.org/image/txb3zeymf/). (Sorry for duplicated comment, don't know if you get notification when i comment others answer) – Torkil Vatne Apr 16 '16 at 15:51
  • I have not had issues with tap gesture inside headerview. Olivier is spot on, but this is key: the selector function used must be available (still alive) at run time. Of course as Varun suggests above, the gesture itself is still alive, but not necessarily the selector. – Rowan Gontier Feb 01 '19 at 22:54
0

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.

Varun
  • 759
  • 6
  • 12
  • Hi, thanks for the tip, but it still does not work. I've also tried Oliveier's suggestion, but that does not work either. The buttons does not respond when they are in front of a section header. The buttons that are not in front works. Here's a picture showing that the "Photo Library"-button works, but not the "Take Photo"-button (because the header is behind): [Image of the problem](http://postimg.org/image/txb3zeymf/). – Torkil Vatne Apr 16 '16 at 15:49
  • Instead of adding buttons to tableView, try adding to self.view – Varun Apr 16 '16 at 18:42