UIAlertView的屏幕截图

时间:2014-05-31 15:19:34

标签: ios rendering uialertview

当存在UIAlertView时,我需要获取我的应用的屏幕截图。 在iOS7中我使用

[[self getMainWindow] drawViewHierarchyInRect:[[UIScreen mainScreen] bounds] afterScreenUpdates:NO];

问题是图像变成了尴尬的颜色和奇怪的行为。我得到的图像很糟糕 - 以下是我的形象。

enter image description here

我尝试了很多不同的事情,但没有成功地获得正确的颜色和图像。

在iOS6中,我找不到捕获UIAlertView的方法。实现这一目标的最佳方式是什么?

谢谢!

编辑:

实际上,问题与renderInContext之前的drawViewHierarchyInRect有关。 如果我将其删除,则图像属于警报视图本身,而下方没有视图。如果我在它之前保留渲染,那么图像就是结果。任何想法都将受到高度赞赏。

3 个答案:

答案 0 :(得分:4)

我无法在屏幕截图中捕获UIAlertview和键盘。

我创建了一个有助于捕获窗口所有元素的屏幕截图的函数。

在这里!

- (UIImage *)screenshot
{
    UIWindow *win = appDelegate.window;

    // Also checking for version directly for 3.2(.x) since UIGraphicsBeginImageContextWithOptions appears to exist
    // but can't be used.
    float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];

    // 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
    if (systemVersion >= 4.0f)
    {
        UIGraphicsBeginImageContextWithOptions(win.frame.size, NO, 0);

    } else {
        UIGraphicsBeginImageContext(win.frame.size);
    }

    CGContextRef context = UIGraphicsGetCurrentContext();

    // Iterate over every window from back to front
    //NSInteger count = 0;

    NSMutableArray *arrAllWindow = [[NSMutableArray alloc] init];
    [arrAllWindow addObjectsFromArray:[[UIApplication sharedApplication] windows]]; // This will allow keyboard capturing

    //below code will allow UIAlertview capturing
    if (IS_Ios8)
    {
        if ([[[UIApplication sharedApplication].keyWindow description] hasPrefix:@"<_UIAlertControllerShimPresenterWin"])
        {
            [arrAllWindow addObject:[UIApplication sharedApplication].keyWindow];
        }
    }
    else
    {
        if ([[[UIApplication sharedApplication].keyWindow description] hasPrefix:@"<_UIModalItemHostingWin"])
        {
            [arrAllWindow addObject:[UIApplication sharedApplication].keyWindow];
        }
    }

    for (int i=0;i<arrAllWindow.count; i++)
    {
        UIWindow *window = [arrAllWindow objectAtIndex:i];
        // -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]);

        // Y-offset for the status bar (if it's showing)
        NSInteger yOffset = [UIApplication sharedApplication].statusBarHidden ? 0 : -20;

        // 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 + yOffset);

        [window drawViewHierarchyInRect:win.frame afterScreenUpdates:YES];

        // Restore the context
        CGContextRestoreGState(context);
    }

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

    UIGraphicsEndImageContext();

    return image;
}

答案 1 :(得分:2)

我设法通过捕获UIAlertView窗口本身来实现它。 我忽略drawViewHierarchyInRect支持renderInContext并使用不同的方法呈现UIAlertView窗口:

CGContextSaveGState(UIGraphicsGetCurrentContext());
// Center the context around the window's anchor point
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), [alertView center].x, [alertView center].y);
// Apply the window's transform about the anchor point
CGContextConcatCTM(UIGraphicsGetCurrentContext(), [alertView transform]);

// Y-offset for the status bar (if it's showing)
NSInteger yOffset = 0;
if (![UIApplication sharedApplication].statusBarHidden && !isIOS7)
    yOffset = -20;

// Offset by the portion of the bounds left of and above the anchor point
 CGContextTranslateCTM(UIGraphicsGetCurrentContext(),
                  -[alertView bounds].size.width * [[alertView layer] anchorPoint].x,
                  -[alertView bounds].size.height * [[alertView layer] anchorPoint].y + yOffset);

// Restore the context
[[alertView layer] renderInContext:UIGraphicsGetCurrentContext()];

CGContextRestoreGState(UIGraphicsGetCurrentContext());

我通过注册到UIWindowDidBecomeVisibleNotification并根据获取提醒窗口的窗口前缀 - 在IOS6IOS7之间获得了正确的窗口。

另一个重要问题是主窗口。显然,在IOS7显示UIAlertView时,它会成为主窗口,因此在尝试渲染主窗口时,您只能获得没有其下方视图的警报视图。因此,为了获得正确的主窗口,我修改了我的getMainWindow方法以符合这种情况:

- (UIWindow *)getMainWindow
{
    UIWindow *topWndow = [UIApplication sharedApplication].keyWindow;
    UIViewController *topController = topWndow.rootViewController;

    if (topController == nil || [[topWndow description] hasPrefix:@"<_UIModalItemHostingWin"])
    {
        // The windows in the array are ordered from back to front by window level; thus,
        // the last window in the array is on top of all other app windows.
        for (UIWindow *aWndow in [[UIApplication sharedApplication].windows reverseObjectEnumerator])
        {
            if (![[aWndow description] hasPrefix:@"<_UIModalItemHostingWin"])
            {
                topController = aWndow.rootViewController;
                if (topController)
                    return aWndow;
            }
        }
    }

    return topWndow;
}

现在我有一个适用于ios6 / 7

的警报视图的截图

答案 2 :(得分:0)

我不知道您是想要图像还是快照视图,但如果是后者,则会拍摄屏幕快照以获取警报视图和背景。作为测试,在创建快照之后,我解除了警报并将快照视图添加为子视图,并且从“实时”警报切换到快照视图是无缝的。

@interface ViewController ()
@property (strong,nonatomic) UIAlertView *alert;
@property (strong,nonatomic) UIView *aView;
@end

@implementation ViewController

- (IBAction)showAlert:(UIButton *)sender {
    self.alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"This is my message to test the alert view" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
    [self.alert show];
}


-(void)didPresentAlertView:(UIAlertView *)alertView {
    self.aView = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES];
    [self.alert dismissWithClickedButtonIndex:0 animated:NO];
    [self.view addSubview:self.aView];
}