I have an application, in which I have a UITableView inside a UIView, which is again inside a UIScrollView, so the hierarchy becomes like this:
UIScrollView -> UIView -> UITableView
The data inside my UITableView is filled properly.
Now, my problem is that, When I scroll my UITableView, the UIScrollView's delegate method scrollViewDidEndDecelerating: and scrollViewDidEndDragging:: gets called.
I don't want this behavior, what should I do to stop this behavior?
Any one please Help,
Thank in advance!!!
UITableViewDelegate extends UIScrollViewDelegate. Hence the calling of the delegate methods.
To stop this you can set tableView.tag = 1000; when you alloc the tableView and in the UIScrollViewDelegate methods ( scrollViewDidEndDecelerating: and scrollViewDidEndDragging:: )add this at the very begining:
if(scrollView.tag == 1000)
return;
Because UITableView inherits from UIScrollView. So it shows all the properties and behaviours of UIScrollView. If you dont want this then please do one thing.
Assuming you have another scrollview in your page.
in the viewDidLoad or from the XIB (if you have your tableview in the XIB), set a tag for your tableview.
in code,
self.objYourTableView.tag = 101;
then in the scroll view delegate
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
if(!(scrollView.tag == 101))
{
// Go for your code to run.
}
}
So that your code will skip if it called by the table view. Other cases it works perfect. Hope this will help you.
Related
Is there any way to know, when the UITableView scrolled ? I need something that is the same like scrollViewDidScroll in scrollview.
If you set your UITableView's delegate to self, the view controller should call scrollViewDidScroll() when the view is scrolled:
myTableView.delegate = self
This works because UITableView is a subclass of UIScrollView.
I have a collection view, the datasource delegate works well, but UICollectionViewDelegate:
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didselect");
}
not get called, although i set the delegate (as i did with data source and it worked)
I have to mention that my cell is loaded from a nib and is connected to a subclass of UICollectionViewCell, anyway the cells do not respond to my touch. I enabled the user interaction in the UIImageView that is in my cell.
also :
-(BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"this is caled");
return YES;
}
is not getting called!
as I mentioned I did set:
[self.collectionView setDelegate:self];
and of course
<UICollectionViewDelegate>
also I don't have any touchBegan override ..
UPDATE:
WEIRD! it only gets called if I long press! how can I fix this, I set delaysContentTouches to NO plus i don`t have any gesture recognizers implemented.
help please. thanks.
It looks like there is a UITapGestureRecognizer somewhere up in the view hierarchy. By default, UITapGestureRecognizers consume the touch that they recieve, meaning that it is not passed to the views below it in the hierarchy. You need to find the rogue tap gesture and add this line
tapGestureRecognizer.cancelsTouchesInView = NO;
This will make it pass touches to views below it in the hierarchy, and hopefully solve your problem.
Looks like you've added TapGestureRecognizer somewhere and it prevents selecton of cell. Check them, that should be the problem.
I was facing the same issue, that clicking on the custom UICollectionView Cell, it was not detecting the click.
In my case, the problem was that in the CustomCell's Xib, the userInteraction was enabled and that's why UICollectionview's didSelectItemAtIndexPath was not getting called, instead user tap information was being sent to that particular cell for which I had no handler.
I had a similar issue with PSUICollectionView (this works on iOS5 too) and I fixed it by putting a button on my CollectionViewCell and setting the target of that button
Also add tag's to know which button is pressed.
In my case I had TapRecognizer added in self.view due to which all taps in Screen is recieved at self.view not in collectionViewDidSelect.
So take care of this .
in ur .h file, import CellViewController and add delegate
#import "myColleCell.h"
UIViewController<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
in ur .m file,add the following codes to ur ViewDidLoad,
UINib *cellNib = [UINib nibWithNibName:#"myColleCell" bundle:nil];
[myCollectionView registerNib:cellNib forCellWithReuseIdentifier:#"myColleCell"];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(220, 220)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[myCollectionView setCollectionViewLayout:flowLayout];
and setup cell with ur CellViewController
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier= #"myColleCell";
myColleCell *cell = (myColleCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
[cell setupCell:[dataArray objectAtIndex:indexPath.row]];
//setup cell function methods placed in your CellViewController
return cell;
}
and finally make sure that your cellView, collectionView are set user interactive to YES
Ensure there aren't any objects setting the userInteractionEnabled property to NO on the UICollectionViewController.
Similar to what other people are saying, I had this same problem and it was fixed by removing a call to userInteractionEnabled where the parent view was adding it as a child view controller. I was able to test this by adding a UIButton to the cell and determining that even it couldn't receive the touch events.
Adding here as a reference for other people who are looking for the answer
Short Answer:
Delay the touches of default gesture recognizers associated with the tableview:
if let gestures = tableView.gestureRecognizers{
for gesture in gestures {
gesture.delaysTouchesBegan = true
}
}
Explanation
Every tableview has gesture recognizers associated with it. Which causes the delays of touches to custom UItableView cell. Set the delaysTouchesBegan to true so that the touch can be passed to subviews quickly.
In my case it was CollectionViewController inside UItableViewCell for which collectionView:didSelectItemAtIndexPath was being called with a delay.
Maybe you should use a tap gesture on the collection view.
I have a UITableViewController which contains a View and a Table View Section.
View contains a label that indicates the title of the table.
My problem is that the scroll includes the View. What I want is to keep View static (exclude from scrolling) and to scroll only Table. (I use static cells)
Thanks.
The hierarchy of a UITableViewController is
- UIView
-- UIScrollView
---- UITableView
Initially you're in the UITableView when modifying items, so you'll want to add the portion that you do not want to scroll to the UIView (outside of our scrollView). So you'll need to call super a couple times like this:
[self.superview.superview.view addSubview:viewThatDoesNotScroll];
Since UITableView is a subclass of UIScrollView:
- (void)viewDidLoad {
[super viewDidLoad];
// mySubview is an instance variable, declared in .h file
[self.tableView addSubview:mySubview];
// here goes the rest of your code
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if(scrollView == self.tableView) {
mySubview.frame = CGRectMake(mySubview.frame.origin.x, scrollView.contentOffset.y, mySubview.frame.size.width, mySubview.frame.size.height);
}
}
The code was taken from WWDC '10 or '11 (I don't remember), so I'm sure it's the most appropriate way to do it.
Explanation: In -viewDidLoad you create your view and add it as a subview of your tableView. You can do it in -loadView or -init - it doesn't matter. The most important lines are in the -scrollViewDidScroll: method. This method is called whenever user drags the scrollView, so you can simply set the origin.y of your subview to contentOffset.y of the scrollView.
Do not UITableViewController. Use UIViewController and manage the views outside of the UITableView object. If you need, you can also implement UIViewControllerContainment to manage different views and different view controllers inside your custom view controller.
I have a private table view in my UIViewController as follows
UIViewController<UIScrollViewDelegate, UITableViewDelegate> {
#private
UITableView *gTableView;
...
}
in my implementation i have set
gTableView.delegate=self;
gTableView.dataSource=self;
EDIT
The scrollViewWillBeginDecelerating and scrollViewDidScroll delegates are getting called but not the scrollViewDidScrollToTop.
What am I doing wrong now?
When used with a TableView, scrollViewDidScrollToTop only gets called with a scroll-to-top gesture (a tap on the status bar). Try using scrollViewDidEndDragging or scrollViewDidEndDecelerating to detect if scrollView.contentOffset.y is <= 0
There is a similar question to this but answer is very general, vague.( Detecting UITableView scrolling )
Please don't dismiss. I am looking for concrete solution.
I have UITableView which has editable textfield and PickerView appears when another cell selected.
What I need is to hide firstResponder or PickerView when user starts scrolling this UITableView.
So far in question Detecting UITableView scrolling there's a sugestion that you should subclass UITableView. IF you subsclass UITableView still internal/private UIScrollView is not accessible.
How do I access UITableView's parent ScrollView (without breaking the law)?
Thanks.
You don't need to subclass UITableView to track scrolling. Your UITableViewDelegate can serve as UIScrollViewDelegate as well. So in your delegate class you can implement -scrollViewWillBeginDragging: or whatever UIScrollViewDelegate method you need in your situation. (as actually suggested in the question you mention)
To expand on Vladimir's answer, this is how I implemented this solution:
In .h file:
#interface MyViewController : UIViewController <UIScrollViewDelegate>
In .m file:
- (void)scrollViewWillBeginDragging:(UIScrollView *)activeScrollView {
//logic here
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if (scrollView == myTableView){
// Your code here.....
}
}
I had the same problem, and I got some ideas from the answers above to fix it, but not only the app crashes if I want to refresh while the table view is being scrolled, but also it crashes if I scroll while it's being refreshed. So the extended solution to fix the problem under all circumstances is to:
1.1. Disable scrolling if the user has pressed the refresh button
1.2. Enable scrolling once the refresh process is done
2.1. Disable the refresh button if the user is scrolling
2.2. Enable the refresh button once the user is finished scrolling
To implement the first part (1.1., and 1.2.):
-(void)startReloading:(id)sender
{
...
self.tableView.userInteractionEnabled = NO;
// and the rest of the method implementation
}
-(void)stopReloading:(id)sender
{
self.tableView.userInteractionEnabled = YES;
// and the rest of the method implementation
}
To implement the second part (2.1., and 2.2.):
- (void)scrollViewWillBeginDragging:(UIScrollView *)activeScrollView
{
barButton.enabled = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
barButton.enabled = YES;
}
And as it's explained in the previous answer, UISCrollViewDelegate needs to be set in the .h file:
#interface MyTableViewController : UITableViewController <UIScrollViewDelegate>
P.S. You can use scrollEnabled instead of userInteractionEnabled, but it all depends on what you're doing, but userInteraction is the preferred option.