如何通过缩放呈现UIViewController?

时间:2011-10-07 08:41:26

标签: iphone objective-c ios ipad

在我的iPad应用中,我有一个带有小桌面视图的视图控制器。当您点击表格视图时,它会打开一个模态视图控制器,它是一个更大,更精致的小表视图版本。我想通过将图像缩小到小表视图的大小并将其缩放到全屏大小,然后用“真实”视图替换图像,从大视图控制器的预渲染图像创建动画控制器。

类似的东西:

LargeViewController* lvc = [[LargeViewController alloc] init];
[self presentModalViewController:lvc byZoomingFromRect:CGRectMake(50,50,200,300)];

我知道你可以从视图中生成图像:

- (UIImage *) imageWithView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [[UIScreen mainScreen] scale]); 
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}

但是如何让视图控制器自己绘制(在屏幕外),这样我就可以看到它并在动画中缩放图像以填充屏幕?

提前致谢。

3 个答案:

答案 0 :(得分:3)

我想你想创建自己的动画。上个月我玩过类似的东西。我的解决方案是将自定义视图(可能从视图控制器中获取)添加到当前视图作为叠加层。这也适用于图层。

首先,从“未来”或“现在”视图控制器中获取图像,就像在上面的代码示例中所做的那样。通常,视图控制器内容在渲染到上下文时应该可用。

现在你有了这张照片。图像的操作必须由您完成。

将图像添加到UIImageView。此ImageView可以添加为子视图或图层。现在您有一个图层,您可以在实际用户界面之上自由绘制。有时您必须移动图层或视图,以便它完美地覆盖您的视图。这取决于您的视图设置。如果您正在处理Tableview,添加子视图并不容易。所以最好使用图层。

完成所有工作后,显示没有动画的新视图控制器,以便立即显示。

完成工作后从父视图中删除图层或视图,然后进行清理。

这听起来很复杂,但是一旦你完成了,你就有了一个模板。在“WWDC 2011,会话309介绍Interface Builder故事板”中,苹果推出了“自定义segues”,您可以在其中找到一种机制,准确地说明您想要做什么。下面的代码是旧项目的剪切,并且有点凌乱,必须清理。但是为了表明原则,这应该有效:

-(void) animate {

      static LargeViewController* lvc = [[LargeViewController alloc] init];

      UIGraphicsBeginImageContextWithOptions(self.bounds.size, view.opaque, [[UIScreen mainScreen] scale]); 
     [lvc.view.layer renderInContext:UIGraphicsGetCurrentContext()];

      // Create a ImageView to display your "zoomed" image
      static UIImageView* displayView = [[UIImageView alloc] initWithFrame:self.view.frame];
      static UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();

      // Add your image to the view
      displayView.image = img;

      // insert the view above your actual view, adjust coordinates in the
      // frame property of displayView if overlay is misaligned
      [[self.view] addSubview:displayView];

      // alternatively you can use the layer
      // [self.view.layer addSublayer:displayView.layer];

      // draw the imageView
      [displayView setNeedsDisplay];

      // do something in background. You may create your own
      // construction, i.e. using a timer
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

          NSDate *now = [NSDate date];
          NSTimeInterval animationDuration = 3.;
          NSTimeInterval t = -[now timeIntervalSinceNow];
          while (t < animationDuration) {

              t = -[now timeIntervalSinceNow];

              // Do some animation here, by manipulation the image
              // or the displayView

              // <calculate animation>, do something with img
              // you have exact timing information in t,
              // so you can set the scalefactor derived from t
              // You must not use an UIImage view. You can create your own view
              // and do sth. in draw rect. Do whatever you want,
              // the results will appear
              // in the view if you added a subview
              // or in a layer if you are using the layer

              dispatch_sync(dispatch_get_main_queue(), ^{

                  // display the result
                  displayView.image = img;
                  [displayView setNeedsDisplay];
              });
          }
       });

      // now the animation is done, present the real view controller
      [self presentModalViewController:lvc animated:NO];

      // and clean up here
}

答案 1 :(得分:0)

也许你可以使用像

这样的东西
CGAffineTransform tr = CGAffineTransformScale(lvc.view.transform, 0.5, 0.5);

在父视图控制器中嵌入缩小版本的视图,然后以模态方式显示lvc并在用户点击视图时恢复缩放。

答案 2 :(得分:0)

UIKit会为您完成大部分工作。虽然jbat100的解决方案也可以使用,但您应该只需将lvc的初始帧设置为您想要开始的较小的矩形,然后将帧设置为其全尺寸时,用于更改框架的隐式动画将为您处理缩放动画。每个UIView都有一个CALayer,其内容被绘制出来,并且该图层有几个隐式动画设置,可以对某些属性(如帧或位置属性)进行动画更改。这是我未经测试的抨击:

       .
       .
   lvc.view.frame = CGRectMake(50,50,200,300);
   [self performSelector:@selector(setFrameToFullScreen) withObject:nil afterDelay:0];

}

- (void)setFrameToFullScreen {
   lcv.view.frame = [UIScreen mainScreen].bounds;
}

performSelector:withObject:afterDelay调用将导致在下一个运行循环周期中调用setFrameToFullScreen。如果你不做那样的事情,那么只会使用最后的帧,系统将无法识别帧中的变化并将其隐式动画应用于视图层。