tableView cells can't be selected with hitTest: WithEvent: - ios

I have a map and above it UIScrollView with a subview of an UITableView (there is a map and you can scroll the tableView up and down on the screen using the scrollView).
I'm using -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event to detect rather the user touches the tableView or the map in the background (if he's scrolling the tableView it will go up and down and if he's scrolling the map the map will change the position (like any regular map)).
The code:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint comparePoint=CGPointMake(point.x, point.y-[[UIScreen mainScreen] bounds].size.height+self.allCellsHeightDividedBy2);
if (comparePoint.y<self.contentOffsetRecivied.y) {
return nil;
}
return self;
}
It's all working fine but the problem is that you can't select a cell in the tableView for some reason, it just don't select it.
Does anybody have an idea? Thanks!

hitTest:withEvent: is supposed to return the deepest subview which the point intersects with. Since you're only returning self, subviews can't be touched.
You should probably replace return self; with return [super hitTest:point withEvent:event].

Related

UIScrollView with custom paging size don't allow clickable buttons

I'm trying to create a scrollview with paging that is smaller than the screen size to snap between the buttons in my scrollview. After much headache and searching I found a solution to create the custom paging size explained below. The problem is the buttons inside my scrollview aren't clickable because the hitTest is overriding it?
This answer solves half the problem https://stackoverflow.com/a/6948934/12264367 ... the code works to create the snapping effect but my buttons aren't clickable I'm guessing because the hitTest but I'm not sure how to fix that?
-(UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event
{
UIView* child = [super hitTest:point withEvent:event];
if (child == self && self.subviews.count > 0)
{
return self.subviews[0];
}
return child;
}

Pass touches on some part of UICollectionView to underlying views

First take a look at the attacthed image:
My hiearchy looks as following:
UIView
UIButton
UICollectionView
UICollectionViewCell
UICollectionViewCell
UICollectionViewCell
UICollectionViewCell
UICollectionView is added to UIVew as H:[collectionView(==270)]| and V:|-(70)-[collectionView]-(70)-|.
I have two requirements:
1) only the blue part of the UICollectionViewCell should trigger the collectionView::didSelectItemAtIndexPath: method. Which I have sucesfully implemented with
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:point withEvent:event];
if (hitView == self.customView) {
return self;
}
return nil;
}
on the custom class UIColectionViewCell. The customView property is the blue/red UIView of the cell.
This works as expected.
2) I want any gestures (Tap/LongTap/Pan/...) that are done in the green part of the UICollectionViewCell or in the UICollectionVIew itself (the background that is here white with 0.5 opacity) to be passed down to the superview. For Example the turquoise UIButtion below.
The green part should also not scroll the CollectionView .. it just has to be completly transparent to any gestures.
How can I do that? Tried a lot of different approaches but none of them worked. I know how to do it with a regular UIView, but cannot get it to work on a UICollectionView and its cells.
Keep in mind that there will be other UIViews or UIButtions that will be interactable and placed under the green part of collection view. The green color will later just be UIClearColor.
Suggestion to just have the UICollectionView smaller width (width of the blue part) is not an option since the Blue/Red part of UICell has to strecth out to full width of the cell in some cases.
Here is the final solution for above example:
1) Require only red/blue part to be tappable.
This stays basically the same. I have a reference to the blue/red UIView names customView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:point withEvent:event];
if (hitView == self.customView) {
return self;
}
return nil;
}
2) Any interactions inside the UICollectionView that are not done on blue/red UIViews should be ignored.
Subclassing UICollectionView and adding overwriting this metod:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
NSIndexPath *indexPath = [self indexPathForItemAtPoint:point];
LCollectionViewCell *cell = (LCollectionViewCell*)[self cellForItemAtIndexPath:indexPath];
if (cell && [self convertPoint:point toView:cell.customView].x >= 0) {
return YES;
}
return NO;
}
This will check if the CGPoint is done on the customView. With this we are also supporting variable widths:
Your answer helped me a ton, thanks!
Here's the solution in Swift 3.0:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let hitView = super.hitTest(point, with: event)
if hitView == self.customView {
return self
}
return nil
}

UITableView will not respond tap after scroll horizontally

I have a UITableView which is embedded in the root view of the ViewController. This UITableView contains multiple columns. And these columns can not be shown in one screen, so I make the UITableView can scroll horizontally. Here is the code which make the tableview scrolling horizontally:
- (void)viewDidAppear:(BOOL)animated
{
CGSize size = self.tableView.contentSize;
size.width = 450;
self.tableView.contentSize = size;
[self.tableView layoutIfNeeded];
}
This works fine and the table can scroll horizontally and vertically. And in the original screen(where no scroll happening), I can select one row and the selected row can be highlighted.
What my problem is: If I scroll the UITableView a little bit left, and in the area where is not shown before scrolling, the tap event cannot be responded by the UITableView. And thus, the row under my finger will not be selected and highlighted. But I can scroll if I swipe in the same area.
Anyone knows what I am doing wrong? Appreciated for your comments and thanks in advance.
I understand your problem and there is always a simple way to do a complex problem.Your required functionality can be achieved by using UICollectionView.
In your UITableViewCell add UICollectionView.In this approach your code will get cleaner and you can achieve your functionality without any headache.
Here is very simple tutorial about UICollectionView.
http://www.appcoda.com/ios-programming-uicollectionview-tutorial/
At last, I think this is a bug of UITableView. I get a workaround for the problem by subclass UITableView. Here it is:
// in my own UITableView subclass .m file
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(#"MonthDetailTableView: touchesEnded");
UITouch * touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
if (point.x < self.frame.size.width)
{
[super touchesEnded:touches withEvent:event];
}
else
{
// if not adjust by mod, the NSIndexPath returned by indexPathForRowAtPoint
// will be nil. I think this is a bug of UITableView
point.x = (int)point.x % (int)self.frame.size.width;
NSIndexPath *path = [self indexPathForRowAtPoint:point];
[self selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
if (self.delegate != nil &&
[self.delegate respondsToSelector:#selector(tableView:didSelectRowAtIndexPath:)])
{
[self.delegate tableView:self didSelectRowAtIndexPath:path];
}
}
}

Nested UIScrollView with pagingEnabled on the encompassing one doesn't receive the first bottom swipe after page change

I'am facing a little problem with my App that has a bit complicated structure :
So first things first the views hirearchy :
|- UICollectionView (horizontal scrolling)
-> UICollectionViewCell
|-> UIScrollView A (PagingEnabled = YES, vertical scrolling only)
|-> UIImageView = page 1
|-> UIScrollView B (PagingEnabled = NO, vertical scrolling only) = page 2
|-> UIView (content...)
The problem is that when I scroll on UIScrollView A to make page 2 appear, the first scroll to the see the bottom on UIScrollView B is ignored, no scroll at all, but the second one has the right behaviour.
I think that it's a kind of "focusing" problem, but I can't figure out how to make this work properly.
Any clue on how to give this first touch on page 2 to the right UIScrollView ?
Have you tried hitTest:withEvent: method? This method helps you choose which view should receive the touch.
For example, you could subclass UIScrollView and set your UIScrollView A's class the new class you just created. Adding the code below to this custom UIScrollView class will let you deliver the touch to it's child view's first
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
for (UIView *subView in self.subviews) {
// Convert the point to the subView's coordinate system.
CGPoint pointForTargetView = [subView convertPoint:point fromView:self];
if (CGRectContainsPoint(subView.bounds, pointForTargetView)) {
// Calling subView's hitTest:withEvent get the right view
return [subView hitTest:pointForTargetView withEvent:event];
}
}
UIView *hitView = [super hitTest:point withEvent:event];
// // Uncomment if you want to make the view 'transparent' to touches:
// // meaning the parts of the view without any subview will deliver the touch
// // to the views 'behind' it
// if (hitView == self) {
// return nil;
// }
return hitView;
}
For more detailed info please check WWDC - Advanced Scrollviews and Touch Handling Techniques (around 15:00 is where this subject starts).
Also, thanks to Tim Arnold for the clue.

custom UIView in UITableViewCell blocks uitableviewcell from reciving an event

I have a custom UITableViewCell i.e. I subclassed UITableViewCell class
when populating each cell (or row) of the uitableview, i am creating my custom UITableViewCell, which composes of an image and some labels.
now when I override the following method in my custom 'UITableViewCell' class,
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"CLICKED CLICKED CELL CLICKED CLICKED");
[super touchesBegan:touches withEvent:event];
}
it never gets called if i click on the custom views i added to the my custom uitableviecell, but it is fine (event triggered) when i click on the region where there is no custom view on top of it.
my goal is simple, i want to detect any touches in each row (uitableviewcell) in the uitableview.
I have experienced a similar problem today, I was unable to select the cell, since it had a custom UIView with a scrollView on it. Try setting userInteractionIsEnabled = false on your subviews of your UIView.
plz try to override this method
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event {}

Resources