Imagine a large table view that's mostly transparent, with some elements here and there. (Perhaps there's a large gap between cells, or, picture the cells being mainly transparent with only a couple buttons or such.
Behind this mostly-transparent table is some other materials, say with some buttons.
How to make the table that
if you scroll it scrolls normally
if you tap on a button on a cell, that works normally
but if you tap on one of the buttons behind the table, the click is passed through and affects that button?
(By "click" I mean what we now call a "primary action triggered" - a "click on a UIButton".)
There are a number of different well-known techniques for passing touches (as such) through views in different situations,
etc.
But I've never been able to get the above three mentioned conditions working.
Summary: enable clicking on a UIButton behind a UITableView.
The "background" buttons should work fully correctly as buttons in all phases, ie if you eg. hold down but then slide off.
Is there a way?
It occurs to me that passing clicks through a scroll view, to buttons behind, is an almost identical problem.



The following code demonstrates the ability to have a table view with a transparent background that allows you to tap on controls in the table view rows, it allows the table view to be scrolled, it allows table view rows to be selected, and it allows for controls behind the table view to be tapped as long as the tap is outside of any controls in a table view row.
The demonstration makes use of modern cell configuration using a custom
UIContentConfigurationand customUIContentView(modeled after this answer). It also makes use of a customUITableViewsubclass.Both the custom table view subclass and the custom cell content view implement custom hit testing based on the solution provided by Pass touches through a UIViewController but with some modification.
Begin by creating a new iOS app project. Setup the project to be based on Swift and Storyboard.
The following code contains lots of comments. The majority of the code below is to setup a working demonstration. The important code is the custom
hitTestmethod inPassTableViewandButtonContentView. Just about everything can be changed as needed except those two methods. Note that the implementation doesn't depend on the table view transparency. That just allows you to see the controls behind the table view.Add a new Swift file named
PassTableView.swiftwith the following contents:Add another Swift file named
ButtonCell.swiftwith the following contents:Last, replace the contents of the provided
ViewController.swiftwith the following:The code supports iOS 15+. Adjust your app's deployment target as needed.
Build and run the app. You will see a table view with 10 rows, each containing a button. You will also see two other buttons labeled "Background ButtonX". The two extra buttons are behind the transparent table view.
All table view interactions work as expected including scrolling and cell selection. Tapping any button, including the two behind the table view, will print a message to the console.
I already state this in the code comments but it is worth repeating. It's critical that the view passed to the
touchDelegateused by the table view and the cells must not be in the table view's superview hierarchy, such asself.view. ThetouchDelegatemust be a sibling (or cousin) view. Violating this condition will lead to infinite recursion when tapping outside of a control in a cell.This general solution also works with
UIScrollView. Create aPassScrollViewsubclass with the same code asPassTableView. That's it. It's much simpler since you don't need to deal with table cells.