On top of my UICollectionViewCells in my UICollectionView I've overlaid a UIButton that intercepts touches so I can respond to touch events more granularly. The issue is that now the collection view no longer gets didSelectItemAtIndexPath messages. (For obvious reasons... the button has absorbed the touch and isn't signaling to the collection view that the item was selected.)
Is there a way to signal to the collection view that the cell was selected? I've seen similar questions but none seem to give a convincing answer.
You can override the pointInside:withEvent: message on UIView [and subclasses] and return false to continue propagating the touch event.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instm/UIView/pointInside:withEvent:
class PassThroughButton: UIButton {
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
// do something
// then continue event propigation
return false
}
}
Related
How do I allow my tableView to be selectable by overriding hitTest?
I have a tableview that lives outside of bounds of its superview so I need to override hitTest of the view containing the superview. However, when I pass the tableview's hittest I can only scroll and not tap on a row.
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let pointInTableview = tableView.convert(point, from: self)
guard tableView.bounds.contains(pointInTableview) else {
return super.hitTest(point, with: event)
}
return tableView.hitTest(pointInTableview, with: event)
}
The datasource and delegates are set. If I manually call tableview.selectRowAt(..) I am able to receive the delegate callback.
Gif of demo
The VC View is the view that is overriding hitTest. We are trying to pass the touches to the tableview because the tableview is outside the bounds of the view it lives in.
The problem wasn't the hitTest.
My VC View had a tap gesture to close keyboards. This tap gesture was cancelling the tableview's tap gesture.
Ref: https://kakubei.github.io/2016/02/24/Tap-Gesture-and-TableView/
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
I have a custom button and it's added to a static cell. Somehow whenever I tap the button, it doesn't react immediately like when the button is added to a plain normal view.
When tapped, it registers the tap right away but the background color has a slight delay before changing.
To change the color I have the following code in my subclass of UIButton:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
border.fillColor = .redColor() // border is a CAShapeLayer
print("began") // This prints right when the button is clicked
}
This button is added in a subclass of UITableViewCell and the button is reacting, except changing the color has a delay. How can I fix this?
Answer (by Jelly):
The answer of Jelly helped me a lot and made the button react a bit better. Knowing what the problem is also made it easier to research the problem and found out to make the button react just as it would in a normal view I have to disable both delaysContentTouches in the table view and it's subviews:
tableView.delaysContentTouches = false
tableView.subviews.forEach { ($0 as? UIScrollView)?.delaysContentTouches = false }
Set delaysContentTouches = false on your tableView.
I am trying to build similar controller to GMSPlacePicker.
I have Map View on background, then Table View with transparent header view. The problem is that all gestures (tap, pan) within header view are passed to table view. I wanna disable them, so all touches will go directly to map view.
I am able to do it If I set:
tableView.userInteractionEnabled = false
but now I am not able to scroll table view.
The question is how to disable all gesture only for header view, but keep getting them for table view.
Basically I wanna get the following behaviour: https://youtu.be/iSBbEZXDyGg
The trick was to create subclass of UITableView and override
func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView?
ANTableView.swift
import UIKit
class ANTableView: UITableView
{
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView?
{
let headerViewFrame = tableHeaderView!.convertRect(tableHeaderView!.frame, toView: self)
if CGRectContainsPoint(headerViewFrame, point) {
return nil
}
return self
}
}
You need to put your map inside the header view. Not behind it.
In iOS 6, I have a UITableView, with pull to refresh enabled. In the top cell, I have a couple of customs controls which the user can interactive by dragging a circular slider (see this example). See screenshot...
The control need a tag and dragging of the slider indicators need to be dragged but they can be tricky to grab as the hit seems to often be on the cell background, causing the table dragging to kick in.
I would like to disable the default scrolling of table if the tap event happens anywhere on those controls. Two options I can think off:
disable table dragging for any event within that top cell
make sure the controls handles events on an larger area, in particular in parts where they have a transparent background
Any suggestions on how to achieve either of these?
Thanks!
I used to subclass of UIControl and override these functions:
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { }
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {}
It works fine for me of this circle slider style.
If still doesn't work you can try to turn on/off your tableView scrollable in the methods above.
tableView.isScrollEnabled = false / true