n.evermind
n.evermind

Reputation: 12004

Objective-C: How to programme a consecutive series of events

Objective-C drives me slightly crazy. I know that it is not a language which processes every command after the other, but what if I need to do this?

For instance, my problem is that I would like to:

  1. Take a screenshot of my current iPhone screen
  2. Before adding this screenshot to my screen, I would like to add another view
  3. Then add the screenshot so that the other view is HIDDEN BENEATH
  4. Then have an animation which slides the screenshot out of view and reveals what is HIDDEN BENEATH

Right now, the app will take a screenshot of all the views added in the method (completely ignoring my order of the events) and will not HIDE the added view BENEATH my screenshot. Whatever I try to do, everything will always happen at once and this sucks.

This is my code:

- (void)takeScreenShot
{
    screenShotView = [[UIImageView alloc] initWithImage:[self screenshot]];
    [screenShotView setFrame:CGRectMake(0, -20, 320, 480)];

    accessoryView.hidden = YES;
    [self.view addSubview:accessoryView]; // which is hidden beneath and about to be revealed
    [self.view addSubview:screenShotView];

    [self.view bringSubviewToFront:screenShotView];

    [self startAnimation];
}

- (void)startAnimation
{
    [UIView animateWithDuration:0.0
                          delay:0
                        options:UIViewAnimationOptionCurveEaseIn
                     animations:^{

                         accessoryView.hidden = NO;

                     }
                     completion:^(BOOL finished){
                         [UIView animateWithDuration:3.0
                                               delay:0
                                             options:UIViewAnimationOptionCurveLinear
                                          animations:^{
                                              screenShotView.transform = CGAffineTransformMakeTranslation(-320, 0);   
                                          }
                                          completion:^(BOOL finished){                                        
                                          }
                          ];    
                     }];
}



- (UIImage*)screenshot 
{
    // Create a graphics context with the target size
    // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
    // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
    CGSize imageSize = [[UIScreen mainScreen] bounds].size;
    if (NULL != UIGraphicsBeginImageContextWithOptions)
        UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
    else
        UIGraphicsBeginImageContext(imageSize);

    CGContextRef context = UIGraphicsGetCurrentContext();

    // Iterate over every window from back to front
    for (UIWindow *window in [[UIApplication sharedApplication] windows]) 
    {
        if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen])
        {
            // -renderInContext: renders in the coordinate space of the layer,
            // so we must first apply the layer's geometry to the graphics context
            CGContextSaveGState(context);
            // Center the context around the window's anchor point
            CGContextTranslateCTM(context, [window center].x, [window center].y);
            // Apply the window's transform about the anchor point
            CGContextConcatCTM(context, [window transform]);
            // Offset by the portion of the bounds left of and above the anchor point
            CGContextTranslateCTM(context,
                                  -[window bounds].size.width * [[window layer] anchorPoint].x,
                                  -[window bounds].size.height * [[window layer] anchorPoint].y);

            // Render the layer hierarchy to the current context
            [[window layer] renderInContext:context];

            // Restore the context
            CGContextRestoreGState(context);
        }
    }

    // Retrieve the screenshot image
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;
}

Upvotes: 2

Views: 570

Answers (1)

Nick Weaver
Nick Weaver

Reputation: 47241

This is no real answer but comments don't offer enough space.

I just recreated a simple project to see if the order of adding the views does any difference to the screenshot.

I used a view based application template. The nib has two buttons, connected to properties btn1 and btn2. See screenshot 1. The upper button btn1 is connect to an action to start taking the screenshot and adding it below the buttons to see a difference. The second button is hidden initially.

screenshot 1

enter image description here

Here is my code of the viewController. myView is your accessory view, which will be created on viewWillAppear. This view contains a label as you'll see later.

Header

...

@interface ScreenshotviewsViewController : UIViewController 
{
    UIButton *btn1;
    UIButton *btn2;

    UIView *myView;
}

@property (nonatomic ,retain) IBOutlet UIButton *btn1;
@property (nonatomic ,retain) IBOutlet UIButton *btn2;
@property (nonatomic ,retain) UIView *myView;

- (IBAction)doTheThings;

@end

I'll skip your screenshot method: nothing changed, works like a charm :). Result in screenshot 2

  • take screenshot
  • show btn2
  • add myView as subview
  • add screenshot as subview

As you can see, the screenshot does not show the other views. I just added it below the buttons to see the differences.

Implementation: case 1

- (void)viewWillAppear:(BOOL)animated
{
    self.myView = [[[UIView alloc] initWithFrame:CGRectMake(0, 20, 320, 50)] autorelease];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, 200, 40)];
    myView.backgroundColor = [UIColor greenColor];
    [myView addSubview:label];

    label.text = @"fooo";

    [label release];
}

- (IBAction)doTheThings
{
    UIImageView *screenShotView = [[UIImageView alloc] initWithImage:[self screenshot]];
    [screenShotView setFrame:CGRectMake(0, 230, 320, 480)];

    btn2.hidden = NO;

    [self.view addSubview:myView];
    [self.view addSubview:screenShotView];
    [screenShotView release];
}

screenshot 2

enter image description here

case two would be

  • show btn2
  • add myView as subview
  • take screenshot
  • add screenshot as subview

    • (IBAction)doTheThings { btn2.hidden = NO; [self.view addSubview:myView];

      UIImageView *screenShotView = [[UIImageView alloc] initWithImage:[self screenshot]]; [screenShotView setFrame:CGRectMake(0, 230, 320, 480)];

      [self.view addSubview:screenShotView]; [screenShotView release]; }

screenshot 3

enter image description here

As you can see the order is recognized. I've left out the animation though. Remove the animation and see if works then. Else try this in a seperate project like I did and see if it works in isolation. If yes we'll have to dig down into you app more.

Upvotes: 1

Related Questions