ios7新特性--18

介绍
我们有时候可能需要取UIView对象的快照,有几个原因,您可能希望—从动画性能改进上去分享您的应用程序的屏幕截图。现有的方法面临几个问题:
1、        代码不简单
2、        复杂的渲染选项,比如层面罩的难再生
3、        OpenGL层需要特殊的事例代码
4、        快照处理十分慢
事实上,真的没有任何通用的“快照”代码可以应付所有可能的场景。
但是IOS7将会改变,UIView和UIScreen会有一些新的方法,为各种用例提供简单的快照功能。

动画快照
我们可能经常想对一个视图进行动画处理,但是视图的动画太复杂,要么是动画太密集,要么就是需要额外的代码来控制正确的行为。
例如附带的项目,我们创建一个UIView的子类,它只是简单的添加一些子视图,并旋转来生成一个有趣的几何排列。
1.png 

使用下面方法构造:
01 - (void)generateRotations
02 {
03     for (CGFloat angle = 0; angle < 2 * M_PI; angle += M_PI / 20.0) {
04         UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 250)];
05         newView.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
06         newView.layer.borderColor = [UIColor grayColor].CGColor;
07         newView.layer.borderWidth = 1;
08         newView.backgroundColor = [UIColor colorWithWhite:0.8 alpha:0.4];
09         newView.transform = CGAffineTransformMakeRotation(angle);
10         newView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
11         [self addSubview:newView];
12     }
13 }


创建这个视图过程中,我不是很建议用这个方法去创建这种效果,或者也许是有用的,但是它确实证明了一个观点。
在视图控制器中,我们将创建一些使用方法,这些方法在项目中会频繁使用。第一个是创建一个旋转视图并添加到主视图上:
1 (void)createComplexView { _complexView = [[SCRotatingViews alloc] initWithFrame:self.view.bounds]; [self.containerView addSubview:_complexView]; }

第二个是个简单的动画方法,用一个提供的视图把它的大小动画缩减到(0,0):
1 (void)animateViewAwayAndReset:(UIView *)view { [UIView animateWithDuration:2.0 animations:^{ view.bounds = CGRectZero; } completion:^(BOOL finished) { [view removeFromSuperview]; [self performSelector:@selector(createComplexView) withObject:nil afterDelay:1]; }]; }

当动画结束,移除这个提供的视图。然后延迟一段时间,重新创建一个新的_complexView去重置应用。
接下来的方法是关联到工具栏的按钮上,按钮的名字为“Animate”。
1 - (IBAction)handleAnimate:(id)sender { [self animateViewAwayAndReset:_complexView]; }

下面的图片演示了我们动画旋转创建视图时的问题:
2.png 
这个问题可以解决,但需要改变SCRotatingViews 构造方法。
当然新的快照方法来解救这里了。下面的方法关联到“SShot”工具栏的按钮上:
1 - (IBAction)handleSnapshot:(id)sender { UIView *snapshotView = [_complexView snapshotViewAfterScreenUpdates:NO]; [self.containerView addSubview:snapshotView]; [_complexView removeFromSuperview]; [self animateViewAwayAndReset:snapshotView]; }

我们调用snapshotViewAfterScreenUpdates:方法去创建复杂视图的快照。方法返回一个UIView,来呈现被调用的视图的界面。用这个方法去获取视图快照非常有效,比制作位图要快的多。
当获得视图快照后,我们把它添加到容器视图上,并移除实际的复杂视图。然后可以动画处理快照视图了:
3.png 
前后视图更新
snapshotViewAfterScreenUpdates:方法有一个BOOL参数,表示是否立即获得快照,或者是否首先处理挂起视图的更新。
例如,在SCRotatingViews 类中添加下面方法:
1 - (void)recolorSubviews:(UIColor *)newColor { for (UIView *subview in self.subviews) { subview.backgroundColor = newColor; } }

当调用时,重置所有子视图的背景色。
为了演示快照方法参数的效果,我们在视图控制器上创建了2个方法,分别绑定到“Pre”和“Post”工具栏的按钮上:
1 -        (IBAction)handlePreUpdateSnapshot:(id)sender { // Change the views[_complexView recolorSubviews:[[UIColor redColor] colorWithAlphaComponent:0.3]]; // Take a snapshot. Don't wait for changes to be appliedUIView *snapshotView = [_complexView snapshotViewAfterScreenUpdates:NO]; [self.containerView addSubview:snapshotView]; [_complexView removeFromSuperview]; [self animateViewAwayAndReset:snapshotView]; }
2 -        (IBAction)handlePostUpdateSnapshot:(id)sender { // Change the views[_complexView recolorSubviews:[[UIColor redColor] colorWithAlphaComponent:0.3]]; // Take a snapshot. This time, wait for the render changes to be appliedUIView *snapshotView = [_complexView snapshotViewAfterScreenUpdates:YES]; [self.containerView addSubview:snapshotView]; [_complexView removeFromSuperview]; [self animateViewAwayAndReset:snapshotView]; }

两个方法仅仅调用snapshotViewAfterUpdates:方法时参数不同。首先调用recolorSubviews:方法,然后像之前一样处理快照流程。下面图片展示了两种方法的不同行为:
4.png 
正如期待的,设置NO将立即取快照,因此不会调用重置颜色的方法。设置YES时,将在取快照前,允许循环渲染去完成当前的队列变化。

图片快照
当动画时,直接取视图的快照对视图是非常有用的。然而,有时对图片也很有用。例如,我们可能想模糊当前正动画离开的视图。这个方法drawViewHierarchyInRect:afterScreenUpdates:可以达到这个目的。这将允许你在绘图上下文上绘制一个视图,因此从当前视图你可以得到一个位图。值得注意的是,这个方法比 snapshotViewAfterScreenUpdates:这个方法的效率明显低,但如果你需要一个位图,这是最好的方法。
我们关联下面的方法到工具栏的“Image”按钮上:
1 - (IBAction)handleImageSnapshot:(id)sender { // Want to create an image context - the size of complex view and the scale of the device screenUIGraphicsBeginImageContextWithOptions(_complexView.bounds.size, NO, 0.0); // Render our snapshot into the image context[_complexView drawViewHierarchyInRect:_complexView.bounds afterScreenUpdates:NO]; // Grab the image from the contextUIImage *complexViewImage = UIGraphicsGetImageFromCurrentImageContext(); // Finish using the contextUIGraphicsEndImageContext(); UIImageView *iv = [[UIImageView alloc] initWithImage:[self applyBlurToImage:complexViewImage]]; iv.center = _complexView.center; [self.containerView addSubview:iv]; [_complexView removeFromSuperview]; // Let's wait a bit before we animate away[self performSelector:@selector(animateViewAwayAndReset:) withObject:iv afterDelay:1.0]; }


首先,创建一个图形上下文,_complexView正确的大小和比例,然后调用thedrawHierarchyInRect:afterScreenUpdates:方法,第二个参数与之前快照方法一样。
然后把用上下文生成UIImage,这个图形将被展示到UIImageView上,并用相同的模式代替复杂视图并动画展示。用UIImage而不是UIView演示的原因,是因为我们已经创建了一个UIImage作为模糊视图的方法。

1 -        (UIImage *)applyBlurToImage:(UIImage *)image {     CIContext *context = [CIContext contextWithOptions:nil];     CIImage *ci_image = [CIImage imageWithCGImage:image.CGImage];     CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];     [filter setValue:ci_image forKey:kCIInputImageKey];     [filter setValue:@5 forKey:kCIInputRadiusKey];     CIImage *result = [filter valueForKey:kCIOutputImageKey];     CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];     return [UIImage imageWithCGImage:cgImage scale:image.scale orientation:image.imageOrientation]; }


这是一个简单的图形过滤器的应用,仅仅提供高斯过滤器并返回一个新的UIImage。
-        下面就是我们创建的效果:

5.png 
限制
如果你曾经试图取支持OpenGL的UIView的快照,你应该知道这是非常复杂的过程(ShinobiCharts可能比较熟悉这种痛苦)。令人振奋的是新的UIView取快照方法会无缝隙的处理OpenGL。
由于快照方法创建的版本基于屏幕的视图展示,所以我们仅仅能创建在屏幕上的视图快照。也就是说,不可能用这些方法去创建这些你想动画添加进主视图的子视图快照,比如有个替代方法。同样意味着,如果你的视图被屏幕边缘裁剪了,那么你的视图的快照也会被裁剪,例如:
6.png 

总结
在IOS取UIView的快照是非常有用的,在IOS7我们终于有了一个明智的API,可以满足大部分场景取快照。但那并不意味着没有限制。某些场景你仍然需要替代方法,但90%用例可以变得很容易的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值