打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
iOS - 使用ZoomingViewController来放大UIView至全屏
iOS - 使用ZoomingViewController来放大UIView至全屏
ZoomingViewController是一个类,你可以将这个类依附于任何一个存在的视图,之后仅需单击一下就可以将这个视图放大至全屏,或者旋转设备来使全屏视图旋转以及单击使其返回初始视图状态。
介绍
在这个项目中使用ZoomingViewController类来处理放缩视图,如下所示:
在原始视图和全屏视图两者间动态切换是很流畅的而且你可以在全屏下通过旋转设备来使视图转动。
你可以通过将ZoomingViewController类依附于任何一个视图来添加这个变换特性。
你可以在这里下载完整的工程文件:TapZoomRotate.zip
要求
ZoomingViewController类有三个主要的特性:
可以响应触击行为
流畅地在不同的视图之间切换
允许在全屏状态下视图的旋转。
响应触击行为
通常情况下,你不必自己处理触击事件,像buttons或者tableviewcell的控制都有自带的触击检测机制。
在iOS3.2之前版本,检测触击事件意味着要在视图中实现touchesBegan:withEvent:和touchesEnded:withEvent:。这需要很高的技巧因为你必须根据计算来掌握触击的时间和位置以判断是否这个触击是有效的。另外,它还不能很好地支持ZoomingViewController类,因为这个类只是依附与这个视图而不是成为这个视图的一部分。
幸运的是,在IOS3.2中引入的手势识别器使得这个问题变得简单:
[c-sharp] view plaincopy
singleTapGestureRecognizer =
[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(toggleZoom:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:singleTapGestureRecognizer];
流畅地在不同的视图之间切换
首先,我们需要记录初始视图以及它的位置。我们通过在视图位置插入一个代理视图来实现记录。以这种方式,当窗口旋转时,该代理视图也可以跟踪视图的位置。
[cpp] view plaincopy
proxyView = [[UIView alloc] initWithFrame:self.view.frame];
proxyView.hidden = YES;
proxyView.autoresizingMask = self.view.autoresizingMask;
[self.view.superview addSubview:proxyView];
之后,我们需要根据当前窗口坐标计算视图当前的位置。
[cpp] view plaincopy
CGRect frame = [self.view.window convertRect:self.view.frame
fromView:proxyView.superview];
[self.view.window addSubview:self.view];
self.view.frame = frame;
然后我们把视图由当前位置放大至全屏显示。
[cpp] view plaincopy
[UIView
animateWithDuration:0.2
animations:^{
self.view.frame = self.view.window.bounds;
}];
[[UIApplication sharedApplication]
setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationFade];
允许在全屏状态下视图的旋转
ZoomingViewController类并不是UIViewController的子类。尽管它控制视图放大和缩小,但是它不需要借助UIViewController的任何行为。
即使你使这个类成为UIViewController的一个子类,它仍然不允许你使用UIViewController类中的自动处理旋转的行为。原因是shouldAutorotateToInterfaceOrientation:只能被窗口的第一个UIViewController来调用。由于fullscreen视图总是这个窗口的第二个视图,因此UIViewController的自动处理旋转行为不能满足我们转动的需要。
因此我们需要自己实现需旋转。这要求三步:
为确定的转动判断正确的全屏边界
在转动之后利用CGAffineTransform来将当前边界转换为新的边界。
监听UIDeviceOrientationDidChangeNotification,当变化发生时申请新值。
根据转动来获取全屏的边界也是相当简单的。我们需要计算面朝上和面朝下转动的不同——我通过计算状态栏转动来得到(我不会总是使用状态栏以防由于某种原因它与某个设备不同步)
[cpp] view plaincopy
- (CGRect)rotatedWindowBounds
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationFaceUp ||
orientation == UIDeviceOrientationFaceDown)
{
orientation = [UIApplication sharedApplication].statusBarOrientation;
}
if (orientation == UIDeviceOrientationLandscapeLeft ||
orientation == UIDeviceOrientationLandscapeRight)
{
CGRect windowBounds = self.view.window.bounds;
return CGRectMake(0, 0, windowBounds.size.height, windowBounds.size.width);
}
return self.view.window.bounds;
}
在UIDeviceOrientationDidChangeNotification之后,我们申请新的边界值。
不幸的是,申请不同的边界会影响视图中心的坐标。由于最后一步需要申请一个转动变换而且转动总是围绕视图中心进行,所以我们需要变换视图以使得中心保持不变。
[cpp] view plaincopy
- (CGAffineTransform)orientationTransformFromSourceBounds:(CGRect)sourceBounds
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationFaceUp ||
orientation == UIDeviceOrientationFaceDown)
{
orientation = [UIApplication sharedApplication].statusBarOrientation;
}
if (orientation == UIDeviceOrientationPortraitUpsideDown)
{
return CGAffineTransformMakeRotation(M_PI);
}
else if (orientation == UIDeviceOrientationLandscapeLeft)
{
CGRect windowBounds = self.view.window.bounds;
CGAffineTransform result = CGAffineTransformMakeRotation(0.5 * M_PI);
result = CGAffineTransformTranslate(result,
0.5 * (windowBounds.size.height - sourceBounds.size.width),
0.5 * (windowBounds.size.height - sourceBounds.size.width));
return result;
}
else if (orientation == UIDeviceOrientationLandscapeRight)
{
CGRect windowBounds = self.view.window.bounds;
CGAffineTransform result = CGAffineTransformMakeRotation(-0.5 * M_PI);
result = CGAffineTransformTranslate(result,
0.5 * (windowBounds.size.width - sourceBounds.size.height),
0.5 * (windowBounds.size.width - sourceBounds.size.height));
return result;
}
return CGAffineTransformIdentity;
}
最后,我们把这些值交给UIDeviceOrientationDidChangeNotification。监听这个报告是简单的,在全屏显示下我们只需要作为观察者就可以了。
[cpp] view plaincopy
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(deviceRotated:)
name:UIDeviceOrientationDidChangeNotification
object:[UIDevice currentDevice]];
唯一需要注意的一点就是当一个视图转动的时候,它的角后面的视图可能会暴露出来。为了避免这个潜在的不明显的情况,ZoomingViewController类使用一个空视图插入到转动视图的后面,当转动完成,这个空视图会消失。
下面deviceRotated:的实现包含以下的代码,包括创建并插入空视图,响应UIDeviceOrientationDidChangeNotification来实施转动。
[cpp] view plaincopy
CGRect windowBounds = self.view.window.bounds;
UIView *blankingView =
[[[UIView alloc] initWithFrame:
CGRectMake(-0.5 * (windowBounds.size.height - windowBounds.size.width),
0, windowBounds.size.height, windowBounds.size.height)] autorelease];
blankingView.backgroundColor = [UIColor blackColor];
[self.view.superview insertSubview:blankingView belowSubview:self.view];
[UIView animateWithDuration:0.25 animations:^{
self.view.bounds = [self rotatedWindowBounds];
self.view.transform = [self orientationTransformFromSourceBounds:self.view.bounds];
} completion:^(BOOL complete){
[blankingView removeFromSuperview];
}];
结论:
使用ZoomingViewController是很简单的:创建它,设置它的视图,之后视图可以响应触击事件,放大为全屏,在全屏下旋转。你可以将它依附给任何一个视图当你需要全屏显示时。
原文作者:Matt Gallagher
原文链接:http://cocoawithlove.com/2010/09/zoomingviewcontroller-to-animate-uiview.html
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
iOS 之美:透过Delegate ,看UIView与UIViewController之间的关系
从Xib文件加载UIView的5种方式,xib加载uiview5种
iOS:探究视图控制器的转场动画
UINavigationItem表示UINavigationBar中的控件
uiviewController管理UITableView
deinit 没执行
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服