UITableViewCell not intercepting scroll events - ios

I have a tableView in which some cells have a UICollectionView in them (for horizontal carousels). It works great for every cell except for one in which the tableView can't be scrolled (either in simulator or on device). To be more exact, the scroll is possible if the touch occurs on the UICollectionViewCell, but not if it occurs on the portion of the UITableViewCell that doesn't contain the UICollectionVIew.
I'd like to find out why that is, but I'm not sure how to go about debugging this. Is there a breakpoint, maybe a symbolic breakpoint, that I can set to understand where the touch events go?
I tried printing stuff in these 3 methods (from the cell itself) to see how and when they were called, but there are not called.
override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
I am not sure posting code is relevant. It's a complex view with lots imbricated parts. I'd rather prefer any debugging technique that would be helpful in this situation.
Thank you very much!
EDIT
Here's more precisions:
There are no other gestures than the ones of the UITableView and UICollectionView.
My view hierarchy is like this:
|--- UITableViewCell --------------|
|-|---cell's content view -------|-|
|-|-|---container view --------|-|-|
|-|-|-|---labels ------------|-|-|-|
|-|-|-|---collection view ---|-|-|-|
|-|-|-|----------------------|-|-|-|
|----------------------------------|
The container view inside the cell's content view has its purpose. But I feel like it is that view that block the scroll gestures.
Apart from isUserInteractionEnable = true, is there anything else that could block gestures events to go up the superviews? This container view doesn't have any gestures attached to it.

I finally made it work by changing the background color of the container view from .clear to some gray.
I'm confused that it works, because transparent views (color: .clear) are supposed to participate in the event responder chain. But that being said, everything was set to .clear, from the container view to the tableView. So the color that was displaying was the viewController's background color.
I'm not sure if it was a bad setup on my part or a bug in UIKit, though. I'd guess it's on me? Anyway... I'm leaving this here in case somebody else runs into this issue.

Related

Avoid Passing Touch Event to the Background View Behind

View
StackView (vertical)
Purple (View)
Green (View)
Orange (View)
View has a tap gesture recognizer. It prints "this" plus a random int.
If I tap Purple, Green or Orange, it still prints "this".
How can I disable taps on the colored boxes? I tried turning off the 'User Interaction Enabled' setting on the boxes.
Because the stack view is a sub-view of View and not added over the top (like a presented view controller), its going to receive the touch events like you're experiencing. Your view controller needs to adopt the UIGestureRecognizerDelegate protocol, then you need to set the gesture's delegate to the view controller (most likely you just need to set it to "self") and then implement the following function:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
//the below will return false if the touch's view is not the gesture recognizer's view
return touch.view == gestureRecognizer.view
}
The code example was referenced from: UITapGestureRecognizer tap on self.view but ignore subviews

UISearchBar Sometimes Resigns When Tapping On Views

My view controller setup is as follows: UISearchBar on top of screen, keyboard on the bottom, and other views between them: custom UIView, UIView, UITableView. When I tap on the table view cells and UIButtons inside UIViews, I can trigger my actions successfully while keeping UISearchBar still visible on screen. But when I tap on UIViews that do not have buttons, this triggers searchBarShouldEndEditing as if search bar loses the focus. I want to disable this behavior and let only Cancel button and keyboard's Done button to trigger UISearchBar closure.
I thought this has to do with bubbling effect and tried to implement this fix:
extension UIViewController : UIGestureRecognizerDelegate{
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
#IBAction func didTap(_ gestureRecognizer : UITapGestureRecognizer ) {
//
}
but this did not address the issue and UISearchBar still calls searchBarShouldEndEditing. Of course, I could add logic to searchBarShouldEndEditing to return false but not sure this is effective enough.
How can I ensure UISearchBar remains in place while tapping on other elements like UIViews?

Transfer gestures on a UIView to a UITableView in Swift - iOS

I have a layout with a UIView at the top of the page and, right below it, I have a UITableView.
What I am wanting to do is to transfer the gesture interactions on the UIView to the UITableView, so when the user makes a drag up/down on the UIView, the UITableView scrolls vertically.
I tried the following code
tableView.gestureRecognizers?.forEach { uiView.addGestureRecognizer($0) }
but it removed the gestureRecognizers from the UITableView somehow :/
Obs.: the UIView cannot be a Header of the UIScrollView
That's Tricky
What is problem ?
Your top view is not allowed to pass through view behind it...
What would be possible solutions
pass all touches to view behind it (Seems to not possible or very tough practically )
Tell window to ignore touches on top view (Easy one)
Second option is better and easy.
So What you need to do is create subclass of UIView and override
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?
and return nil if you found same view on hitTest action
Here Tested and working example
class PassThroughME : UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return super.hitTest(point, with: event) == self ? nil : self
}
}
That's it now use PassThroughME either by adding class to your view in storyboard or programmatically whatever way you have added your view
Check image i have black color view with 0.7 alpha on top still i am able to scroll
Hope it is helpful

Is it possible to make Tap Gesture Recognizer work if UIImageView it's connected to is under UIScrollView?

Please take a look on a screenshot
I have a UIImageView with Tap Gesture Recognizer connected to it ("Mans body image view"). When I tap this UIImage I want it to call a keyboard with colors so I can change skin color of this mans figure.
For now it does not work because on top of Mans body image view I have 4 scroll views which are responsible for hair, facial hair and clothing (tops and bottoms).
Is there any way I can make Tap Gesture Recognizer (under scroll views) to react on my taps?
Thank you
Make a UIScrollView subclass and implement
func gesture​Recognizer(UIGesture​Recognizer, should​Recognize​Simultaneously​With:​ UIGesture​Recognizer)
Asks the delegate if two gesture recognizers should be allowed to recognize gestures simultaneously.
func gestureRecognizer(_ gestureRecognizer: UIPanGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UISwipeGestureRecognizer) -> Bool {
return true
}
or use horizontal UICollectionView instead and implement delegate method didSelectItemAtIndexPath.

UICollectionView: Measure force on tap of cell

I am working on a tiny project where I want to use the 3D touch screen pressure capabilities (e.g. touch.force).
Right now I can measure force in my ViewController and it is behaving like I want it:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
if traitCollection.forceTouchCapability == UIForceTouchCapability.available {
// 3D Touch capable
let force = touch.force
print("Force: " + force.description)
}
}
}
I have one UIImageView that presents a picture. I also use an custom UICollectionView as overlay, which contains transparent cells and colored cells. What I am trying to achieve is to measure both force, and be able to remove the color from the cells when they are pressed, but I am failing to do both. I can either measure force, or change the color of a cell in the UICollectionView, but not both.
The solution as I see it is to forward touches from the UICollectionView to the next view in the hierarchy. But another solution could be to measure both force and register taps on cells from within the custom UICollectionView.
My question is, is either of my proposed solutions any good? And if so, how do I achieve them?
Apparently the override func touches... methods are part of UIView, not neccesarily UIViewControllers. This means that implementing the touchesMoved and other methods into my custom UICollectionView is perfectly possible and it solved my problem of handling touches and taps at the same time.

Resources