开发者

Pass Control (Responder?) back to Lower UIView whilst Still Performing Fade Out Animation on Upper UIView

From all of the view controllers within my application if I am processing a long running task I present the user a 'progress view'. This is a UIView that lives in my MainWindow.xib. I show (fade in) the view using an AppDelegate method...

 - (void)showProgressView 
 {
     self.progressView.hidden = NO;

     [UIView animateWithDuration:1.0 
                      animations:^(void) { self.progressView.alpha = 1.0; }];
 }

When the long running task has finished I fade out the 'progress view' with the following AppDelegate method...

 - (void)hideProgressView 
 {    
    [UIView animateWithDuration:1.0
                     animations:^(void) { self.progressView.alpha = 0.0; }
                     completion:^(BOOL f) { self.progressView.hidden = YES; } 
                     }];
 }

My problem is that as the progress view fades away and as the buttons/controls in the under-lying view below become visible again they ARE NOT usable (they don't respond to touch events) until the animation has fully finished and the 'progress view' is hidden.

Is there anyway for me to pass control back to the underlying view, before starting the fade out animation, so that its buttons etc do work whilst the progress view fades away?

EDIT: Things I have already tried unsuccessfully...

Using resignFirstResponder

- (BOOL)findAndResignFirstResponder:(UIView*)view
{
    NSLog(@"looping %@", [view description]);
    if (view.isFirstResponder) 
    {
        [view resignFirstResponder];
        return YES;
    }

    for (UIView *subView in view.subviews) 
    {
        if ([self findAndResignFirstResponder: subView])
        {
            return YES;
        }
    }

    return NO;
}

 - (void)hideProgressView 
 {    
    // Recursively attempt to remove control from the progress view
    BOOL result = [self findAndResignFirstResponder:self.progressView];

    [UIVie开发者_如何学运维w animateWithDuration:1.0
                     animations:^(void) { self.progressView.alpha = 0.0; }
                     completion:^(BOOL f) { self.progressView.hidden = YES; } 
                     }];
 }

Using endEditing

 - (void)hideProgressView 
 {    
    // Attempt to remove control from the progress view
    [self.progressView endEditing:YES];

    [UIView animateWithDuration:1.0
                     animations:^(void) { self.progressView.alpha = 0.0; }
                     completion:^(BOOL f) { self.progressView.hidden = YES; } 
                     }];
 }


You can try sending your progress view the message resignFirstResponder. This should make the view below it the first responder, so you can use its controls.

PS: I also think that maybe your progress view could be filling the whole display; in this case, changing the first responder might not help...

EDIT: after you confirmed that your view is taking the full screen...

If your view is full screen, it is intercepting all the touches that you do (because when it is not fully hidden/transparent it is covering the views behind it). You have two options, either you make the view smaller, so that you have no overlapping, or you make so that the touches are forwarded to the view behind it.

You can do the latter in several ways, I hope that one works for you:

  1. you can try and override in your progress view (it needs be a custom UIView), the touchesBegan method;

  2. you can try and override the hitTest method in your progress view;

This is what I would try, e.g. in touchesBegan:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      if (![self viewIsDisappearing])
           [self.nextResponder touchesBegan:touches withEvent:event];
 }

viewIsDisappearing is a method you should implement to return YES if the animation to hide the progress view has already begun. During the animation the view is not yet hidden, so it will intercept touches, and you forward those touches to the next responder.

It is possible that you also need to override the other UIResponder's touche-related methods:

 – touchesMoved:withEvent:
 – touchesEnded:withEvent:
 – touchesCancelled:withEvent:

EDIT:

I have found a class of mine where I do something similar to what I am suggesting here, only, without using the nextResponder.

The idea is: SDSTransparentView is a UIView that covers the whole screen. You initialize it like this:

 [[SDSTransparentView alloc] initWithContent:contentView andDelegate:delegate];

The delegate implements an SDSTransparentViewProtocol which simply contains one method:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event outsideOfView:(UIView*)view;

When the user touches anywhere on the transparent view, it relays the touch to the delegate by calling the protocol method. I would suggest you to ignore the contentView and outsideOfView arguments (they where useful for me, but possibly not for you; you can either pass nil or, better, the view behind the progress view).

You can find the class on my github. You only need the SDSTransparentView.* files. Actually, I only suggest having a look at how the class is implemented (very short) and do the same in your progress view.

I can assure that this approach works!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜