I have UITableView added as subview of UITableviewCell.
In iOS 6 when I scroll internal tableView and reach to the end of it main table view becomes scrolling.
In iOS 7 it doesn't work anymore. If I am scrolling in internal table view it doesn't deliver this scroll event to parent tableView.
Does anyone know how to simply fix it, without manual transferring event from internal tableview to parent?
Additional info:
I find possible reason of problem. But how to fix this problem.
So, I found a solution.
According to tip from #FaisalAli I implement delegate method:
- (BOOL) gestureRecognizer: (UIGestureRecognizer*)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer: (UIGestureRecognizer*)otherGestureRecognizer
{
if ([gestureRecognizer isKindOfClass: [UIPanGestureRecognizer class]])
{
if ([((UIPanGestureRecognizer*)gestureRecognizer) velocityInView: self].y > 0)
{
// Up
if (self.contentOffset.y <= 0)
{
self.bounces = NO;
return YES;
}
}
else
{
// Down
if (self.contentOffset.y + self.height >= self.contentSize.height)
{
self.bounces = NO;
return YES;
}
}
}
self.bounces = YES;
return NO;
}
And it helped.
I don't think that this is wise solution regarding ease of use for user. You should use Master-Detail Strategy.
Set UINavigationController as rootViewController, then push your Master TableViewController, on selection of each cell you can push new TableViewController having detailed data of selected Cell Item.
Edit
If you really want to add TableView inside a TableViewCell then, please follow link 1 and link 2.
Related
My UIScrollView inside a nested UITableView, in which UITableView has a left row pop-up menu of gestures, and now the two views of the gesture conflict. Now the question is: how to solve this problem without changing the UITableView ?
PS: I have been set UIScrollView ScrollEnabled=false
Your question is different but as you agree that your main problem is conflict between the gestures, that means you are not able to differentiate between gesture of two views,
To solved there are two ways, you need to receive gesture based on condition in gestureRecognizer delegate method, you can either check the class which received the gesture or by checking class or by tag
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
if([touch.view class] == [UITableView class]){
return NO;
} else if (touch.view.tag == 100) {
return NO;
} else if ([NSStringFromClass([touch.view class]) isEqualToString:#"UITableViewCellContentView"]) {
return NO;
}
return YES;
}
What this delegate would do is, it will call the gesture handler method only for the view which you want to handle gesture and also you can differentiate between the gesture recogniser.
I have a custom UICollectionViewCell that has a few custom UIView objects residing inside them. Each of these UIViews has a UIButton which responds to Touch Down and Touch Up Inside linked by IBActions. Basically, I want these buttons to shrink down when pressed down and spring back to their original size when let go. I can easily accomplish this with the controls and the press down and press up works. However, the problem I am facing happens when scrolling is introduced into the mix. The UICollectionView these cells are apart of is a scrolling one. If I happen to touch a button as I start my scroll, the Touch Down event is triggered as well as the scrolling event of the UICollectionView. If I recall correctly, this was never the case pre-iOS7. When a scrolling event was started, the UIButton event wasnt fired off, I think it had to do with the delaysContentTouches. This looks to be broken or changed now. It actually still works decently on iPhone, just not on iPad. If I scroll my view on iPad, with my touch starting inside the embedded UIButton, the button will shrink and the buttons action will be fired off.
So to restate the issue as plainly as I can: Is there anyway to ignore touches on embedded UIButtons when scrolling is occurring? Touches work fine when there is no scrolling triggered, I just dont want the events to fire off if the user is indeed scrolling. Is there any workaround?
If you need any more specific details, I would be happy to help you understand.
you need to subclass scrollView (collectionView or tableView) and override
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:UIButton.class]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
swift
override func touchesShouldCancelInContentView(view: UIView) -> Bool {
if view is UIButton {
return true
}
return super.touchesShouldCancelInContentView(view)
}
thats it now you can scroll over button and not lose button tap event.
In a UICollectionView of mine, buttons inside of UICollectionViewCells registered TouchUpInside-taps even though the UICollectionView was still decelerating, which sounds like a similar problem to what you're having. I created a UIButton subclass that overrides beginTrackingWithTouch:withEvent and will return NO in case the UIScrollView it's contained in is decelerating or dragging.
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
UIView *superView = self;
while((superView = [superView superview])) {
if ([superView isKindOfClass:UIScrollView.class]) {
UIScrollView *scrollView = (UIScrollView *)superView;
if (scrollView.isDecelerating || scrollView.isDragging) {
return NO;
}
}
}
return [super beginTrackingWithTouch:touch withEvent:event];
}
The easiest thing to try that comes to mind is to check if the UIScrollView (your UICollectionView) is scrolling or dragging when the button action is triggered.
if(! self.collectionView.dragging && ! self.collectionView.decelerating)
{
// do action because we are not moving
}
Have you tried that?
I have two horizontal UIScrollViews with PagingEnabled.
In a portrait mode everything works fine, but in landscape I'm getting a conflict between scroll views. For example if current visible view is ScrollView2.View2 and I'm scrolling to the ScrollView1.View3, ScrollView2 scrolling as well as ScrollView1. It somehow receives the event of scrolling of ScrollView1. In result I'm getting the ScrollView2.contentOffset equal to 0.0 (but it should be equal to X of View2, for example 384.0).
Is it possible to determine which scroll is scrolling? I tried to fix with UIScrollViewDelegate methods, but didn't help me and things get even worse if I put WebViews instead of Views.
EDIT: I have added a small sample to github.
As I mentioned before, I tried to check the instance of the scrollview in "didScroll" and other delegate methods, but it's not easy to sync everything in this methods. And I tried to override hitTest methods, didn't help me either.
scrollViewDidScroll:
Tells the delegate when the user scrolls the
content view within the receiver.
(void)scrollViewDidScroll:(UIScrollView *)scrollView
whats wrong with something like this?
-(void)scrollViewDidScroll:(UIScrollView*)scrollView
{
if(scrollView == ScrollView2)
{
// do stuff
}
}
I haven't find the way of passing the event to the right scrollview. But here is a few things that made it work:
First of all, you need to disable Paging Enabled in all nested UIScrollViews (because nested UIScrollView will be scrolled with parent UIScrollView).
Implement paging of the nested ScrollViews:
/*
* User stopped dragging the innerScroll, the view is not decelerating
* and it is still not at its place. Lets help the view to get into right place.
*/
-(void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if ([scrollView isEqual:innerScroll] && !decelerate) {
if(scrollView.contentOffset.x <= view1.frame.size.width/2){
[innerScroll scrollRectToVisible:view1.frame animated:YES];
} else {
[innerScroll scrollRectToVisible:view2.frame animated:YES];
}
}
}
/*
* User stopped dragging the innerScroll and the View is decelerating.
* Lets skip an efforts of the View to get into right place and put it ourselves.
*/
- (void) scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
if ([scrollView isEqual:innerScroll]) {
if(scrollView.contentOffset.x <= view1.frame.size.width/2){
[innerScroll scrollRectToVisible:view1.frame animated:YES];
} else {
[innerScroll scrollRectToVisible:view2.frame animated:YES];
}
}
}
And disable and enable parent UIScrollViews while you inner UIScrollView haven't reached the last View.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
if([scrollView isEqual:innerScroll]){
if(CGRectIntersectsRect(scrollView.bounds, view1.frame)){
if(CGRectIntersectsRect(filterScroll.bounds, view11.frame)){
} else if(CGRectIntersectsRect(filterScroll.bounds, view22.frame)){
}
mainScroll.scrollEnabled = NO;
} else if (CGRectIntersectsRect(scrollView.bounds, view2.frame)){
mainScroll.scrollEnabled = YES;
}
}
}
I have a UITableView that draws a subView when the user touches a cell.
The problem is that the subView drawing is animated and if the user is fast enough they can tap a cell multiple times which I want to disable during the animation and afterwards.
I've tried using this:
- (void) tableView: (UITableView*) tableView didSelectRowAtIndexPath: (NSIndexPath*) indexPath {
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
and also a bool variable:
if (isAnimating == NO) {
but neither seem to work. In each case rapid touches screws up everything.
Any help would be great thanks!
Try this...
After clicking on cell set
tableView.userInteractionEnabled = NO;
I know this is an old question however it lacked the swift version so,
in Swift 3 it is:
tableView.isUserInteractionEnabled = false;
and to turn it back on is:
tableView.isUserInteractionEnabled = true;
Just thought this might help someone if they were looking for the answer in swift 3 as I was, and ends up here.
I have a scroll view that used to scroll when it didn't have buttons all over it. Now it does, and when dragging the mouse (on simulator) nothing happens (i think because the buttons are being pushed). How can I make this right?
This is happening because UIButton subviews of the UIScrollView (I assume buttons are added as subviews in your case) are tracking the touches and not the scroll view. UIScrollView method touchesShouldCancelInContentView is the key here. According to its description: "The default returned value is YES if view is not a UIControl object; otherwise, it returns NO.", i.e. for UIControl objects (buttons), UIScrollView does not attempt to cancel touches which prevents scrolling.
So, to allow scrolling with buttons:
Make sure UIScrollView property canCancelContentTouches is set to YES.
Subclass UIScrollView and override touchesShouldCancelInContentView to return YES when content view object is a UIButton, like this:
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
if ( [view isKindOfClass:[UIButton class]] ) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
I founded this question looking for the swift solution for this problem, I "translated" it like this:
Swift 5
class UIButtonScrollView: UIScrollView {
override func touchesShouldCancel(in view: UIView) -> Bool {
if view.isKind(of: UIButton.self) {
return true
}
return super.touchesShouldCancel(in: view)
}
}
hope this could help
Swift 3 Solution
override func touchesShouldCancel(in view: UIView) -> Bool {
if view is UIButton {
return true
}
return super.touchesShouldCancel(in: view)
}
One thing to try if you're seeing this in a simulator is to run on an actual phone. I couldn't scroll in the simulator but no prob on my phone.
In my case, I solved it with this way.
in ViewDidLoad
self.scrollView.panGestureRecognizer.delaysTouchesBegan = self.scrollView.delaysContentTouches;
in .m
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:[UIControl class]]) return YES;
return NO;
}