Search code examples
xcodeuiviewdelegatesuiscrollviewibaction

Disable scrolling via IBAction contained in subview


My iPad app is currently built as such: xml data is pulled from my website and parsed in a View Controller "FishIDView". This view controller has a UIScrollView "scrollView" that has a subview "XMLView" which is a UIView. scrollView is setup so that it scrolls and pages through the XMLViews based on the number of items contained in the XML. For example 12 items = 12 pages, or instances of XMLView. These pages contain photos of individual fish. Each of these pages contain a button that creates a subview of the UIView "XMLView" called "flipView", and displays the subview via the flip from left animated transition. This subview contains information about the pictured fish. flipView has a button that returns the user (flips back) to the fish picture.

My problem is that when I'm looking at the flipView (which is a subview of XMLView which is a subview of scrollView), scrolling is still enabled. If I scroll left or right while on flipView, I see the XMLView of the next fish. I want scrolling to be disabled while looking at flipView.

Any suggestions on what I can do to send something like a setScrollEnabled:NO command to scrollView (on FishIDView) from the subview?

EDIT:

So I assume I need to use a protocol and delegate. I thought I could figure it out, but I'm getting caught up on the implementation.

In my XMLView.h (leaving out extraneous code):

@protocol XMLViewDelegate <NSObject>

- (void) stopScrolling;

@end

@interface XMLView : UIView 
{
    ...
    id                      secondDelegate;
}
...
@property (nonatomic, retain) id <XMLViewDelegate>    secondDelegate;
...

@end

Then in my XMLView.m (with the IBAction hooked to a UIButton which works correctly):

...
@synthesize secondDelegate;
...
-(IBAction)goToInfo
{
    //[self newPage];
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self cache:YES];
    [self.secondDelegate stopScrolling];
    [self addSubview:flipView];
    ...

    NSLog(@"button pressed");

}

In FishIDView.h:

@interface FishIDView : UIViewController <XMLViewDelegate>

FishIDView.m:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [scrollView setScrollEnabled:YES];

    XMLView *subsubView = [[XMLView alloc] init];
    subsubView.secondDelegate = self;
    ...
}

-(void) stopScrolling
{
    [scrollView setScrollEnabled:NO];
    NSLog(@"NO more scrolling!!!");
}

When I click on my button in XMLView that triggers "goToInfo", the rest of the action happens, but the log "No more scrolling!!" never displays.

Did I go about this the wrong way? I'm still trying to figure out delegates, so I may be completely wrong with this methodology.

EDIT 2:

I've now tried getting rid of the delegate and going what sounds like a more simplistic route, but it's still not working correctly.

In XMLView.m:

-(IBAction)goToInfo
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self cache:YES];

    //The next 2 lines are what I added
    ViewController *mainView = [[ViewController alloc] init];
    [mainView stopScrolling];

    [self addSubview:flipView];
    [infoButton setEnabled:FALSE];
    [infoButton setHidden:YES];
    [title setHidden:YES];
    [UIView commitAnimations];

    NSLog(@"button pressed");

}

Then in FishIDView.h

-(void) stopScrolling;

FishIDView.m

-(void) stopScrolling
{
    [scrollView setScrollEnabled:NO];
    NSLog(@"NO more scrolling!!!");
}

The "No more scrolling!!!" prints, but scrollView is still scroll enabled! Why would it run the NSLog portion of stopScrolling but not setScrollEnabled:NO? Can anyone help me?


Solution

  • Solved! I incorporated Notifications instead of trying to directly call a method from a subview.

    Quick overview of my setup. UIViewController FishIDView contains a UIScrollView called scrollView. scrollView has a subview XMLView. XMLView has a button that shows its subview, flipView. I wanted scrolling to be disabled on scrollView when flipView was visible.

    In XMLView.h (with irrelevant code omitted):

    #import <UIKit/UIKit.h>
    #import <QuartzCore/QuartzCore.h>
    
    #define kApplicationDidStopScrollingNotification @"StopScroll"
    #define kApplicationDidResumeScrollingNotification @"ResumeScroll"
    
    #import "FishIDView.h"
    
    @interface XMLView : UIView 
    {
        IBOutlet UIButton       *infoButton;
        IBOutlet UIButton       *closeButton;
        IBOutlet UIView         *flipView; 
    }
    
    @property (nonatomic, retain) IBOutlet UIButton       *infoButton;
    @property (nonatomic, retain) IBOutlet UIButton       *closeButton;
    
    - (IBAction)goToInfo;
    
    - (IBAction)closeSubView;
    
    @end
    

    In XMLView.m:

    #import "XMLView.h"
    
    @implementation XMLView
    
    @synthesize infoButton, closeButton;
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            // Initialization code
        }
        return self;
    }
    
    //Allows button to be pressed while contained in subview of scrollview
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        CGPoint hitPoint = [infoButton convertPoint:point fromView:self];
        CGPoint closePoint = [closeButton convertPoint:point fromView:flipView];
        if ([infoButton pointInside:hitPoint withEvent:event]) return infoButton;
        if ([closeButton pointInside:closePoint withEvent:event]) return closeButton;
        return [super hitTest:point withEvent:event];  
    }
    
    -(IBAction)goToInfo
    {
        //post notification for FishIDView to listen to to trigger method that disables scrolling
        [[NSNotificationCenter defaultCenter] postNotificationName:kApplicationDidStopScrollingNotification object:nil];
    
        [self addSubview:flipView];
    
        //custom transition between views. A cross-fade effect
        flipView.alpha = 0.0f;
        [UIView beginAnimations:@"fadeInSecondView" context:NULL];
        [UIView setAnimationDuration:0.5];
        flipView.alpha = 1.0f;
    
        [infoButton setEnabled:FALSE];
    
        [UIView commitAnimations];   
    }
    
    - (IBAction)closeSubView
    {
        //post notification to resume scrolling
        [[NSNotificationCenter defaultCenter] postNotificationName:kApplicationDidResumeScrollingNotification object:nil];
    
        flipView.alpha = 1.0f;
        [UIView beginAnimations:@"fadeInSecondView" context:NULL];
        [UIView setAnimationDuration:0.5];
        flipView.alpha = 0.0f;
    
        [infoButton setEnabled:TRUE];
    
        [UIView commitAnimations];
        [flipView performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1.2];
    
    }
    
    @end
    

    Make sure to put #import "XMLView.h" into your FishIDView.h file at the top and create the -(void) methods at the bottom.

    #import <UIKit/UIKit.h>
    
    #import "XMLView.h"
    
    @class AppDelegate;
    
    @interface FishIDView : UIViewController <UIScrollViewDelegate>
    {
    ...
    }
    
    @property ...
    
    //These are the 2 methods that turn scrolling on and off
    -(void) stopScrolling;
    -(void) resumeScrolling;
    
    @end
    

    Then in FishIDView.m

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [scrollView setScrollEnabled:YES];
    
        //Listen for the notification to stop scrolling
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stopScrolling) name:kApplicationDidStopScrollingNotification object:nil];
    
        //Listen for the notification to resume scrolling
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeScrolling) name:kApplicationDidResumeScrollingNotification object:nil];
        [self layoutSubview];
    }
    
    -(void) stopScrolling
    {    
        [scrollView setScrollEnabled:NO];
        NSLog(@"NO more scrolling!!!");
    }
    
    -(void) resumeScrolling
    {    
        [scrollView setScrollEnabled:YES];
        NSLog(@"begin scrolling again!!");
    }
    

    If anyone has questions or is having trouble implementing this, I'll be happy to share more of my code. I just omitted most of it because it doesn't really pertain to this subject.