如何在自己的应用程序中进行长截屏?
不知道各位在开发过程中是否碰到过此类的需求,产品要求开发人员将长长的文章或者是浏览的内容进行截屏然后将截图所获得的图片分享出去或者上传到服务器。
笔者遇到了这样一个需求,要求开发人员将配置好的商品发送出去的同时截图上传至服务器。然后以此作为一个记录,便于日后方便取用。看了并简单写了一个测试demo试了一下。
// 长截图 类型可以是 tableView或者scrollView 等可以滚动的视图 根据需要自己改
- (void)saveLongImage:(UITableView *)table {
UIImage* image = nil;
// 下面方法,第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了,调整清晰度。
UIGraphicsBeginImageContextWithOptions(table.contentSize, YES, [UIScreen mainScreen].scale);
CGPoint savedContentOffset = table.contentOffset;
CGRect savedFrame = table.frame;
table.contentOffset = CGPointZero;
table.frame = CGRectMake(0, 0, table.contentSize.width, table.contentSize.height);
[table.layer renderInContext: UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
table.contentOffset = savedContentOffset;
table.frame = savedFrame;
UIGraphicsEndImageContext();
if (image != nil) {
//保存图片到相册
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
}
重点是获取所要截屏的长度和宽度大小。即使获取屏幕上控件的高度加在一起。获取将要裁剪的尺寸。那么如果截图成功了。如何将图片保存呢?
// 保存后回调方法
- (void)image: (UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
NSString *msg = nil ;
if(error != NULL){
msg = @"保存图片失败" ;
}else{
msg = @"保存图片成功,可到相册查看" ;
}
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:@"确定" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated:YES completion:nil];
}
微信可以检测到用户截屏行为(Home + Power),并在稍后点击附加功能按钮时询问用户是否要发送刚才截屏的图片,这个用户体验非常好。于是乎, 我也想着实现这个功能。
在iOS7之前, 如果用户截屏,系统会自动取消屏幕上的所有 touch 事件,(使用touchesCancelled:withEvent: 这个方法)那么我们就可以检测这个方法的调用,然后加载本地最新图片再加以判断来实现我们的目的。但在 iOS 7 之后,截屏不再会取消屏幕的 touch 事件,所以导致了 Snapchat 和 Facebook Poke 之类的应用在 iOS 7 刚发布时依赖于系统这个行为的功能受到影响。
如果不采取任何新措施, 我们可以让应用启动后在后台循环检测相册内最新一张照片,看它的是否符合截屏的特征。这种方法可行,但这是个笨方法,需要用户允许你的程序访问相册才可以,并且一直在后台循环会消耗更多的系统资源。
当然, 苹果封闭了一些东西, 肯定也会给你开放其他东西, 不会让你走上绝路的。
iOS7提供一个崭新的推送方法:
UIApplicationUserDidTakeScreenshotNotification
。只要像往常一样订阅即可知道什么时候截图了。
注意:UIApplicationUserDidTakeScreenshotNotification
将会在截图完成之后显示
。现在在截图截取之前无法得到通知。
一。注册通知:
//注册通知[[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector(userDidTakeScreenshot:)name:UIApplicationUserDidTakeScreenshotNotificationobject:nil];
二。监听截屏:
执行操作, 也就是实现上面通知对应的响应函数 -- userDidTakeScreenshot
//截屏响应- (void)userDidTakeScreenshot:(NSNotification*)notification{NSLog(@"检测到截屏");//人为截屏, 模拟用户截屏行为, 获取所截图片UIImage*image_ = [selfimageWithScreenshot];//添加显示UIImageView*imgvPhoto = [[UIImageViewalloc]initWithImage:image_]; imgvPhoto.frame =CGRectMake(self.window.frame.size.width/2,self.window.frame.size.height/2,self.window.frame.size.width/2,self.window.frame.size.height/2);//添加边框CALayer* layer = [imgvPhoto layer]; layer.borderColor = [ [UIColorwhiteColor]CGColor]; layer.borderWidth =5.0f;//添加四个边阴影imgvPhoto.layer.shadowColor = [UIColorblackColor].CGColor; imgvPhoto.layer.shadowOffset =CGSizeMake(0,0); imgvPhoto.layer.shadowOpacity =0.5; imgvPhoto.layer.shadowRadius =10.0;//添加两个边阴影imgvPhoto.layer.shadowColor = [UIColorblackColor].CGColor; imgvPhoto.layer.shadowOffset =CGSizeMake(4,4); imgvPhoto.layer.shadowOpacity =0.5; imgvPhoto.layer.shadowRadius =2.0; [self.window addSubview:imgvPhoto];}
我这里的 userDidTakeScreenshot 总共做了3件事
1.打印检测到截屏
2.获取截屏图片。调用[self imageWithScreenshot];这里的imageWithScreenshot是人为截屏, 模拟用户截屏操作, 获取截屏图片。
3.显示截屏图片, 以屏幕1/4大小显示在右下角, 并且加上白色边框和阴影效果突出显示。
三。获取截屏图片
/**
* 截取当前屏幕
*
* @return NSData *
*/- (NSData*)dataWithScreenshotInPNGFormat{CGSizeimageSize =CGSizeZero;UIInterfaceOrientationorientation = [UIApplicationsharedApplication].statusBarOrientation;if(UIInterfaceOrientationIsPortrait(orientation))imageSize = [UIScreenmainScreen].bounds.size;elseimageSize =CGSizeMake([UIScreenmainScreen].bounds.size.height, [UIScreenmainScreen].bounds.size.width);UIGraphicsBeginImageContextWithOptions(imageSize,NO,0);CGContextRefcontext =UIGraphicsGetCurrentContext();for(UIWindow*windowin[[UIApplicationsharedApplication] windows]){CGContextSaveGState(context);CGContextTranslateCTM(context, window.center.x, window.center.y);CGContextConcatCTM(context, window.transform);CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);if(orientation ==UIInterfaceOrientationLandscapeLeft){CGContextRotateCTM(context, M_PI_2);CGContextTranslateCTM(context,0, -imageSize.width);}elseif(orientation ==UIInterfaceOrientationLandscapeRight){CGContextRotateCTM(context, -M_PI_2);CGContextTranslateCTM(context, -imageSize.height,0);}elseif(orientation ==UIInterfaceOrientationPortraitUpsideDown) {CGContextRotateCTM(context, M_PI);CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);}if([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]){[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];}else{[window.layer renderInContext:context];}CGContextRestoreGState(context);}UIImage*image =UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();returnUIImagePNGRepresentation(image);}/**
* 返回截取到的图片
*
* @return UIImage *
*/- (UIImage*)imageWithScreenshot{NSData*imageData = [selfdataWithScreenshotInPNGFormat];return[UIImageimageWithData:imageData];}