views:

273

answers:

2

I'm making a partial overlay modal in my app with the code from “Semi-Modal (Transparent) Dialogs on the iPhone” at ramin.firoozye.com. In doing so, the button that calls the modal is still visible and clickable. I will hide this button when the modal spawns, but I want to be sure if the user clicks very quickly twice, a new modal doesn't come up for each click. What is the best way to check that the modal doesn't already exist when calling it from the button click?

You can download the test project here. For those that don't have xcode, the relevant functions are below:

I call forth the modal on button click with this:

- (IBAction)displayModal:(id)sender {
    ModalViewController *modalController = [[ModalViewController alloc] initWithNibName:@"ModalViewController" bundle:nil];
    modalController.view.frame = CGRectOffset(modalController.view.frame, 0, 230);
    [self showModal:modalController.view];
}

Then use this function to animate the custom modal over the current view:

- (void)showModal:(UIView*) modalView {
    UIWindow* mainWindow = (((TestAppDelegate*) [UIApplication sharedApplication].delegate).window);

    CGPoint middleCenter = modalView.center;
    CGSize offSize = [UIScreen mainScreen].bounds.size;
    CGPoint offScreenCenter = CGPointMake(offSize.width / 2.0, offSize.height * 1.5);
    modalView.center = offScreenCenter; // we start off-screen
    [mainWindow addSubview:modalView];

    // Show it with a transition effect
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.4]; // animation duration in seconds
    modalView.center = middleCenter;
    [UIView commitAnimations];
}

Then I dismiss the modal on button click with this:

- (IBAction)dismissModal:(id)sender {
    [self hideModal:self.view];
}

And then use these functions to animate the modal offscreen and clean itself up:

- (void)hideModal:(UIView*) modalView {
    CGSize offSize = [UIScreen mainScreen].bounds.size;
    CGPoint offScreenCenter = CGPointMake(offSize.width / 2.0, offSize.height * 1.5);
    [UIView beginAnimations:nil context:modalView];
    [UIView setAnimationDuration:0.7];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(hideModalEnded:finished:context:)];
    modalView.center = offScreenCenter;
    [UIView commitAnimations];
}

- (void)hideModalEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
    UIView* modalView = (UIView *)context;
    [modalView removeFromSuperview];
    [self release];
}

Any help is greatly appreciated!

A: 

If I understand your question, you can just do: Sender.hidden=YES; As the first line in the IBAction

Else, you could have a BOOL ivar in your header like this:

{
    BOOL isShowingModal;
}

And put in an if statement in displayModal, and set isShowingModal to YES

And in hideModal, set it to NO

Tom H
I suppose I'll have to put my hide functions in the same class as the show functions in order to maintain that conditional. Thanks for the added tip about hiding the button, but Sender.hidden errors that sender is undeclared. [sender setHidden:YES]; compiles, but triggers an unrecognized selector sent to instance error. Any ideas?
Cuzog
From what I can tell, UIBarButtonItems can't be hidden. They can only be set to nil then reinitialized. I intend to hide the entire nav bar when the modal displays anyway, which thankfully has a built-in method to handle that.
Cuzog
Ah... Yes, I remember always getting very annoyed that the compiler wouldn't let you use the property dot syntax on the id type (even when it would actually work). I know it won't help now, but for the future if you define the method like this:-(IBAction)doWhatever:(UIBarButtonItem *)senderthen it'll work just fine. I though you were using a UIButton, which to the best of my knowledge can be hidden. Hope you manage it! Another method (although you've already got a working one) could be to use the delegate pattern, and set the view which has the bar as the delegate of the modal.
Tom H
Oh really? I didn't know the app could have more than one delegate. Thanks for the tips!
Cuzog
Oh, I wasn't referring to the app delegate. You know that any object can have a delegate or be a delegate? Some objects such as a uitableview, have a delegate which you assign to them. When an event happens in the table view, such as the user tapping a row, the table view calls a method on its delegate, have a look at uitableviewdelegate documentation for an example. If you want more information, I'd be pleased to provide it, as delegation was a really confusing topic to me when I started.
Tom H
Interesting! That makes things a lot clearer to me. I’ll take you up on that if I get stuck trying to implement one. You’ve really gone above and beyond to help me with this. Thanks again!
Cuzog
A: 

I really didn't want to resort to a global variable to keep track of the modal already existing, so I decided to use notification.

I put this in my navigation controller where I call the modal:

- (void)viewDidLoad {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notShowingModal) name:@"ModalDidClose" object:nil];
    [super viewDidLoad];
}

- (void)notShowingModal {
    isShowingModal = NO;
}

Then I put this in the modal controller where the modal is dismissed:

- (void)viewDidDisappear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ModalDidClose" object:nil];
}

I could probably do it with the AppDelegate as well. If anyone thinks that, or anything else, would be a better fit for this, let me know.

Cuzog