如何通过缩放的方式展示一个UIViewController?

9
在我的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个回答

3
我想您想要创建自己的动画。上个月我也尝试了类似的事情。我的解决方案是将自定义视图(可能来自视图控制器)作为覆盖添加到当前视图中。这也适用于图层。
首先,像您在上面的代码示例中所做的那样,从“未来”或“现在”视图控制器中获取图像。通常,在渲染到上下文时应该可以使用视图控制器的内容。
现在您有了图像。必须由您来处理图像的操作。
将图像添加到UIImageView中。此ImageView可以添加为子视图或图层。现在,您有一个图层,可以在实际用户界面上自由绘制。有时,您需要移动图层或视图,以便完全覆盖您的视图。这取决于您的视图设置。如果您正在处理Tableviews,则添加子视图不太容易。因此最好使用图层。
完成所有工作后,立即呈现新的视图控制器,而不使用动画。
在完成工作后,从父视图中删除图层或视图,并进行清理。
这听起来很复杂,但一旦您完成了这项工作,就会有一个模板可供使用。在“WWDC 2011,Session 309 Introducing Interface Builder Storyboarding”中,苹果介绍了“自定义segue”,其中您将找到一个完全符合您要求的机制。下面的代码是旧项目的剪辑,有些凌乱,需要进行清理。但是为了展示原则,这应该可以工作:
-(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
}

终于有时间测试了你非常详细的建议。效果非常好!非常感谢你的帮助!另外,WWDC 2011会议上关于自定义转场的309演讲也很棒。 - Påhl Melin

0

也许你可以使用类似这样的东西

CGAffineTransform tr = CGAffineTransformScale(lvc.view.transform, 0.5, 0.5);

如果要将视图的缩小版本嵌入到您的父视图控制器中,那么请以模态方式展示lvc,并在用户点击视图时恢复比例。


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 在下一个运行循环周期中被调用。如果您不这样做,那么只有最终的框架将被使用,系统将无法识别框架的变化并将其隐式动画应用于视图层。


问题在于视图控制器没有框架属性,因为它不是一个视图类。我知道显示视图控制器的唯一方法是使用 presentModalViewController:animated: 方法,而该方法会自行设置动画。 - Påhl Melin
没错! 视图控制器本身没有框架,但其视图有。我已编辑上面的代码以反映这一点。 - Logachu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接