tableView:canEditRowAtIndexPath difficult to receive event - ios

I have a customised cell that need to receive the swipe event so it can show the delete button on the right side.
It is an iPad application.
The problem is that it is very difficult to receive the event. Just when swiping very fast that the delegate is called. In other cells in my project this is not happening.
I tried to remove the views inside the cell and it is still difficult.
Also tried to just return yes on the canEditRowAtIndexPath delegate instead of all my logic inside. But the problem is that the delegate is not called.
I also checked if there is any gesture recogniser that is confusing the default swipe recog.
Anyone has a tip?

I had the same problem using SWRevealViewController, so I canceled the swipe touch using this delegate
- (BOOL)revealControllerPanGestureShouldBegin:(SWRevealViewController *)revealController
{
return NO;
}

Related

Conflict with a UIPanGestureRecognizer on a UITableView's superview

I'm trying to build something roughly similar to the drawer menu in Apple Maps on iOS.
In this Xcode project I'm attaching a UIPanGestureRecognizer on the VC's view, and as the panning happens, move vertically a UITableView with scrolling disabled.
The issue is every time after the pan ends, the didSelectRow method is called only after a second tap happens somewhere on the UITableView. Of course I'd like it to be called after the first tap.
The funny thing is that the bug does not happen if I enable the table's scrolling, and in the gesture recognizer's delegate have shouldRecognizeSimultaneouslyWith returning true.
Other funny thing is a very similar thing seems to happen in Apple Maps itself, if you try pulling the drawer up with the finger resting on a recent location entry from the list inside the drawer.
Thanks for your help!
I don’t understand well what are your saying.
But I think that the main problem is with “Chain Responder”. When you use PanGestureRecognizerand the UITableView property isScrollEnable = false in the Responder Chain the PanGestureRecognizer it is the first who is called, and the system wait to that fails or the event is not handled, then it is passed to the next in the Responder Chain, who is the UITableView. For that reason, it takes too long to get called the didSelectRow function
I suggest to you create a new UIView and insert in the ViewController in the storyboard o nib and put the UITableVIew outside of that UIView, then link the PanGestureRecognizer to that new UIView. In that way the Responder Chain don’t get in conflict with both, because the system can detect when the drag is in the new UIView and call only to the PanGestureRecognizer and when it is in the UITableView will call to the didSelectRow
Best Regards
Write if it does not resolve

UICollectionView didSelectItemAtIndexPath not called when tapped on UITextView

I have a UICollectionView with custom cells- They have a UITextView that mostly covers the entire cell. This presents a problem when using didSelectItemAtIndexPath. The only way to trigger it is by tapping outside the UITextView. I want it to trigger wherever in the cell you tap, whether there is a text view or not. How can this be done?
didSelectItemAtIndexPath is called when none of the subView of collectionViewCell respond to that touch. As the textView respond to those touches, so it won't forward those touches to its superView, so collectionView won't get it.
override hitTest:withEvent method of your collectionViewCell or CollectionView subclass and always return self from them.so it explicitly makes collectionView as first responder.
I would suggest to use UIGestureRecognizer for each cell and when it taped to send it to UITextView or whatever , perhaps there maybe a better solutions , but I would use this 1 because of simplicity reasons.
Do you override touchesEnded: withEvent: ?
I had the same problem today and I found that I have some customised logic in touchesEnded in one of collectionview's container views, and I didn't call
[super touchesEnded: withEvent:]
when I'm done with my customised logic in touchesEnded.
After adding the super call, everything is fine.
Select UITextView, in that specific case UICollectionViewCell, and switch to attribute inspector. The uncheck User interaction enabled and it should work fine.
I ran into this problem when I had a scroll view taking up my entire collection view cell. While all the solutions above probably work fine, I came up with my own elegant work-around. I put a 'select' label under my scroll view. Since the label is not part of the scroll view, it passes the tap event on to the collection view. It also serves as a nice indicator that an action is required of the user.
Just do this
textview.isUserInteractionEnabled = false

UITableView need long press to select a row

Anyone has ever come into the problem that UITableView need long press to trigger the didSelectRowAtIndexPath method?
If you have used any gesture recognizer try to removing it and check if it causing the problem or not ?
Other wise
Not sure but The problem might be in the UITableView has delaysContentTouches turned ON. Turn this OFF so touches get through to the cells faster.
In my situation I had a UITapGestureRecognizer on my view for hiding my keyboard.
This solved the problem:
tap.cancelsTouchesInView = false
I had exactly the same trouble :
I used the Tap Gesture recognizer to manage different action in my View Controller
I wanted a classic tap (short click) to trigger the didSelectRowAtIndexPath method but just a long press working by default
My solution to select a cell in Table View by a short tap (press) :
Select your Tap Gesture recognizer in your Story Board
Go to the attributes inspector and deselect "Canceled in view"
You have to add UILongPressGesture to your cell's view and on fire just call didSelectRowAtIndexPath (better will be to call another method - not standard UITableViewDelegate's method) from your class that adopts UITableViewDelegate.
I will suggest You create own protocol, inherited from UITableViewDelegate, add there method for long press behavior method and enjoy. Something similar to:
#protocol LongPressTableViewCellDelegate <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didLongTapCell:(UITableViewCell *)cell;
#end
Your delegate in this case would adopt not standard UITableViewDelegate, but this one. Also You have to create own cell (inherited from UITableViewCell) and add there delegate property (id ) that will be used when long press fired.
Also there can be situation that standard didSelectRowAtIndexPath will be fired before your long press will fire, so I suggest you to disable standard selection behavior for table view:
_tableView.allowsSelection = NO;

UICollectionView only calling didSelectItemAtIndexPath if user double taps, will not call when user single taps

I have a UICollectionView which is about the size of the screen. The UICollectionViewCells that it displays are the same size as the collectionView. Each cell has a UIImage which is the size of the cell. The CollectionView has paging enabled so essentially it is a full screen photo slideshow that the user can swipe through.
The problem is that
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath is only being called if the user taps with two fingers on a cell or long presses with one finger and then releases. It does not seem to have the default behaviour of single tap selection. I have not made any changes to the CollectionView gesture recognizer so am having trouble finding a solution to this problem.
Are you sure you're not accidentally overriding - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath? "Select" vs. "deselect" has tripped me up in the past with Xcode's code completion.
I was just having the same problem and it turned out that there was a UITapGestureRecognizer on the UIView containing the UICollectionView and it was responding instead.
That explains why didSelectItemAtIndexPath works only if the user taps with two fingers or long presses with one finger because that doesn't trigger the UITapGestureRecognizer.
So, check all the UITapGestureRecognizer you got there, not necessarily on the UICollectionView directly but it could be on any UIView containing it.
If you have a view on the cell which obstructs the cells content view that is intractable then you will not be able to hook into the delegate callback for the cell.
You will want to disable user interaction on the obstructing view either in the NIB or in the code.
view.userInteractionEnabled = NO;
Just add to the already resolved question one more situation where the tap gesture might not work, since this did keep tormenting me.
If you return false within UICollectionViewDelegate's collectionView:shouldHighlightItemAtIndexPath:, the tap gesture won't function and the collectionView:didSelectItemAtIndexPath: would not be called. The default return value of this delegate method is true, so you won't have the problem if you don't implement it deliberately.
I just ran into this problem myself. Originally I had buttons and labels, then I refactored my UI and turned those button/labels into cells for a UICollectionView.
I eventually realized the buttons were consuming my taps. I had unthinkingly just moved my original buttons into the cell, and not turned it into a straight UIImage. I had destroyed the actions associated buttons and was just looking for cell selection so I took me a while to figure it out.
Stupid and obvious in retrospect, but took me a couple hours to realize what I had done.
If you use only didselect:
self.collectionView.allowsMultipleSelection = false
Or delete that line.
I just had the same problem...I was overriding touchesBegan in the CollectionCell view and this caused the didSelectItemAtIndexPath to not fire when I touched the cell. Removed the override and all worked.
In my case it was just
self.collectionView.allowsSelection =NO;
I had in code.
changing to
self.collectionView.allowsSelection =YES;
fix it.
Try removing all of your UIGestures from the view then test to see if the UICollectionView Cells are able to be interacted with normally.
In my case, I had to remove the lines:
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
self.view.addGestureRecognizer(tap)
I ran into this problem in Swift 3 and xcode 8 , I had a view and a collection view inside this.The collection view has userInteractionEnabled to true , still it was not working.Fixed this issue by overriding shouldHighlightItemAt , I dont have any extra / custom implementation in this method , so i did not override this method.After adding the below code the didSelectItem method is called.
func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return true
}
I'm happened to stumble upon this problem, and it frustrated me one long day until I found this You just need to uncheck "User Interaction Enabled"
when I selected the Cell on the top left inside the CollectionView in Storyboard. and problem solved
I faced a similar problem and the culprit in my case turned out to be the CardView I was using in UICollectionView Cell's heirarchy. As soon as I disabled the user interaction for the CardView the collectionView started responding to the touch events.
In case it helps, this just bite me in a silly way spending a couple of hours. Double check if your custom cell is subclassing UICollectionViewCell instead of, let's say, UICollectionReusableView 😂
the top answer works in many cases. but for me, I have a page with complicated gesture, and I met the same situation and the answer does not work for me, finally I got my way:
when adding gestures, set delegate and use this protocal method to deal with it
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
in this method, you can decide whether the gesture recognizer to receive the touch by your own logic, no matter position or the page's hidden property, based on your demand.
once the method return NO, the gesture won't react the touch, in this case the collectionView or tableView can react the selection correctly.
Remember to add UICollectionViewDataSource, UICollectionViewDelegate to the class

iOS: Tapping on UITableView does not call didSelectRowAtIndexPath

My app uses a UITableView with a UINavigationController to show a more detailed view when a row of the table is tapped - the basic drill-down routine.
When I tap on a row, it is highlighted, but the delegate methods tableView:willSelectRowAtIndexPath: or tableView:didSelectRowAtIndexPath: are not called (verified using debugger).
Now here's the weird part:
There are some other table views in the app (they don't drill down) and none of them exhibit the issue.
If I tap the row rapidly and repeatedly, after many tries (10 - 20 is normal), tableView:willSelectRowAtIndexPath: and tableView:didSelectRowAtIndexPath: are called and processing continues normally.
The problem occurs only on an (any, actually) iPad running iOS 6. It works fine with iPads running iOS 5, or with any iPhone running any iOS version, 6. It also works with the iPad simulator using iOS 5 or 6.
So it seems that something is receiving the tap before the delegate methods are called. But what?
I not using any UITapGestureRecognizer, so that is not the issue.
I am not using multiple UITableViewControllers for the table, so this is also not the issue.
I was having this issue with an app when running in iOS6. The tableView:didSelectRowAtIndexPath: method was never being triggered, even though it was working before updating to iOS6.
I finally figured it out by looking at the xib and the attribute inspector for the table. In the Table View section I had the Selection option set to No Selection and Show Selection on Touch was not selected.
Changing the Selection option to Single Selection actually got this working for me again and leaving the Show Selection on Touch unselected means that I don't see any flash or change of colour when the row is selected.
I encountered a similar issue. iOS 6 appears to be much more sensitive to the slightest upward movement on a tap on a table view cell. It appears it is registering the slightest movement as a scroll request rather than a cell selection. My table view was set to scrollEnabled = NO because it is a table view with static selection values. The table view appears within a small area of a larger iPad view. If I carefully tap a cell and lift directly up, the cell is selected.
To resolve it, I changed scrollEnabled to YES and made sure the area dedicated to my tableView was larger than the actual area needed to show the table view, thus preventing it from scrolling. Not sure if this is is the cause of the issue you are experiencing, but hope it helps.
I had the same problem. The UITableView was not triggering the didSelectRowAtIndexPath method when running in iOS6, but it was working fine in iOS5.1.
I had also implemented the
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath{
return NO;
}
and returned NO. In iOS5 it was all working fine, but the minute I switched to iOS6 it would cease to trigger the didSelectRowAtIndexPath. Once I removed that shouldHighlightRow method, everything worked in iOS6 again. Cheers!
The usual reason that didSeletRowAtIndexPath() doesn't get called is having a UITapGestureRecognizer on your viewcontroller with Cancels touches in view set to YES.
The correct and only sensible fix is to set Cancels touches in view to NO. Then your table row selection should work nicely.
Obviously this has some implications in your gesture handlers - you may need to add some code to your gesture handler to stop some touches going on to your views i.e.
- (IBAction)onTapGesture:(UITapGestureRecognizer *)sender {
if (sender.view == someOldViewThatINeedToDealWith) {
sender.cancelsTouchesInView = true;
}
}
I tried all the other answers posted, and although they seemed promising, they didn't solve the problem.
I've since discovered the cause of problem in my case: I was calling [self.tableView reloadData] on a different thread (due to handling an NSNotification event posted from a background worker thread).
I fixed the problem by changing [self.tableView reloadData] to
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
Hope this helps.
The other suspect could be a Tap Gesture Recognizer set to the view controller's view swallowing all taps like a blackhole. Remove the gesture recognizer will enable did select. I just had the same issue and the tap gesture was the cause.
The resolution is really weird: the UITableViewController registered for all notifications. In the handler for the notifications, the table view data was being reloaded using
[self.tableView reloadData]
According to Apple DTS, when the table reloads data, this causes a notification to be sent to the observer, causing a race condition ...
No explanation for why it would work sometimes or why it would always work on an iPhone. But registering only for a small subset of notifications (i.e. the ones I was really interested in) fixed the problem!
Setting
recognizer.cancelsTouchesInView = NO;
takes care of it if your use case allows simultaneous handling
of touches by [tap] gesture recognizer (kdb dismiss for example)
and the view the recognizer is attached to.
in my case I hade button which received all touch events before tableviewcell

Resources