在iPad中显示带自定义框架的模态视图控制器

时间:2010-11-01 00:24:44

标签: ipad ios uiviewcontroller uipopovercontroller modalviewcontroller

我想在iPad中显示一个带有自定义框架的模态UIViewController,以其父视图控制器为中心。

我尝试使用表单,但据我所知,帧和阴影效果无法更改。

vc.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:cv animated:YES];

我也试过使用一个弹出框,但据我所知,要么我不能居中,要么我无法隐藏箭头。

还有另一种显示模态视图控制器的方法吗?是否可以通过使用表单或弹出框来解决此问题?

5 个答案:

答案 0 :(得分:6)

我正在使用以下方法创建一个模式视图控制器,其中任何给定大小都在屏幕中心。如果需要,您可以将其更改为父视图控制器的中心。 这是从故事板开始工作,因此您可以将视图控制器作为参数发送。但除此之外,它可以满足您的需求。

注意:我发现如果你试图在这个上显示另一个模态,它将恢复到原始大小。

- (UIViewController *) presentModalViewControllerWithIdentifier:(NSString *)identifier 
                                                        andSize:(CGSize)size 
                                        andModalTransitionStyle:(UIModalTransitionStyle)modalTransitionStyle {
    UIViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];


    viewController.modalPresentationStyle = UIModalPresentationPageSheet;
    viewController.modalTransitionStyle = modalTransitionStyle;
    [self presentModalViewController:viewController animated:YES];
    viewController.view.superview.autoresizingMask = 
    UIViewAutoresizingFlexibleTopMargin | 
    UIViewAutoresizingFlexibleBottomMargin | 
    UIViewAutoresizingFlexibleLeftMargin | 
    UIViewAutoresizingFlexibleRightMargin;    
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    viewController.view.superview.frame = CGRectMake(0, 0, size.width, size.height);
    CGPoint center = CGPointMake(CGRectGetMidX(screenBounds), CGRectGetMidY(screenBounds));
    viewController.view.superview.center = UIDeviceOrientationIsPortrait(self.interfaceOrientation) ? center : CGPointMake(center.y, center.x);

    return viewController;
}

如果这是你想要的唯一的东西它可以正常工作。 但我发现Apple的模态视图控制器的实现有点适得其反,因为你无法访问它的任何底层部分,因此你无法完全动画它们。如果你想拥有自己的过渡,这很有用。

它也不属于子视图控制器的类别,因为它代表了窗口中的所有其他视图。

答案 1 :(得分:4)

没有正式的方法可以执行此操作,但是您可以通过编写自定义视图来获得所需的行为,该视图使引用或委托与其呈现的视图控制器交互并将其添加到视图层次结构中。要真正获得模态感觉,您还可以在“模态”视图下方的呈现控制器上放置透明覆盖。我已经在许多应用程序中完成了这项工作,它通常效果很好。您可能需要制作自定义叠加视图,以便您可以拦截触摸并更优雅地为其演示设置动画。

我的透明叠加层通常是这样的:

@protocol TransparentOverlayDelegate <NSObject>

@optional
- (void)transparentOverlayWillDismiss:(TransparentOverlay *)backgroundTouch;
- (void)transparentOverlayDidDismiss:(TransparentOverlay *)backgroundTouch;
@end


@interface TransparentOverlay : UIView {

    id<TransparentOverlayDelegate> _delegate;
    UIView *_contentView;
    CGFloat _pAlpha;
}

@property(nonatomic, assign) id<TransparentOverlayDelegate> delegate;
@property(nonatomic, retain) UIView *contentView;
@property(nonatomic, assign) CGFloat pAlpha;

- (void)presentTransparentOverlayInView:(UIView *)view;
- (void)dismissTransparentOverlay:(BOOL)animated;

我的自定义模态视图通常是这样的:

@protocol ModalViewDelegate <NSObject>
- (void)performSelectorOnDelegate:(SEL)selector;
@end

@interface ModalView : UIView {
    id<ModalViewDelegate> _delegate;
}

@property(nonatomic, assign) id<ModalViewDelegate> delegate;

在我的呈现视图控制器中,我通常会执行以下操作:

- (void)presentModalController {
    TransparentOverlay *to = [[[TransparentOverlay alloc] initWithFrame:self.view.bounds] autorelease];
    to.delegate = self;

    ModalView *mv = [[ModalView alloc] initWithFrame:CGRectMake(500, 500, 300, 300)];
    mv.delegate = self;

    to.contentView = mv;
    [mv release];

    [to presentTransparentOverlayInView:self.view]; 
}

使用在这两个类上定义的委托给了我非常开放的权限,可以根据需要操纵我的呈现控制器以及我的演示和解雇。唯一的缺点是当它在带有NavigationBar的视图上使用时,因为呈现控制器视图的边界将不包含NavigationBar的边界,使其保持打开以进行交互,有多种方法可以绕过它而不是它们非常漂亮(添加到导航控制器的视图是一个选项)。

答案 2 :(得分:1)

这可能无法完全回答您的问题。但是我在导航控制器上从右侧按钮调用以下代码,我之前放置在splitviewcontroller的详细视图的顶部。

此模态视图涵盖整个屏幕。例如,您是否只想在detailviewcontroller中调用详细视图?

- (void)aboutAction {

About *about = [[About alloc] init];
UINavigationController *nav1 = [[UINavigationController alloc]initWithRootViewController:about];
[about release];
nav1.navigationBar.barStyle = UIBarStyleBlackOpaque;
nav1.modalPresentationStyle = UIModalPresentationFullScreen;
nav1.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:nav1 animated:YES ];
[nav1 release];

}

答案 3 :(得分:1)

我更喜欢fabio-oliveira的答案,但需要进行一些调整才能使其适用于IOS 7的多线程环境:

- (UIViewController *)presentModalViewControllerWithId:(NSString *)identifier
                                           andSize:(CGSize)size
                           andModalTransitionStyle:(UIModalTransitionStyle)style
{
    UIViewController *viewController = 
            [self.storyboard instantiateViewControllerWithIdentifier:identifier];

    viewController.modalPresentationStyle = UIModalPresentationPageSheet;
    viewController.modalTransitionStyle = style;

    [self presentViewController:viewController animated:YES completion:nil];

    viewController.view.superview.autoresizingMask = 
        UIViewAutoresizingFlexibleTopMargin    |
        UIViewAutoresizingFlexibleBottomMargin | 
        UIViewAutoresizingFlexibleLeftMargin   | 
        UIViewAutoresizingFlexibleRightMargin;

    viewController.view.superview.frame = 
                   CGRectMake(0, 0, size.width, size.height);

   return viewController;
}

现在将居中代码放在目标VC中,以便新线程完成工作:

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    CGPoint center = CGPointMake(CGRectGetMidX(screenBounds),
                                 CGRectGetMidY(screenBounds));

    self.view.superview.center =
    UIDeviceOrientationIsPortrait(self.interfaceOrientation) ? 
                                       center : CGPointMake(center.y, center.x);
}

哦,是的,如果你支持那些可爱的IOS 5 iPad 1,请务必让目标vc旋转:

- (BOOL)shouldAutorotateToInterfaceOrientation:
                         (UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

答案 4 :(得分:1)

就我而言,覆盖viewWillLayoutSubviews就可以了。

- (void)viewWillLayoutSubviews {
        [super viewWillLayoutSubviews];

    self.view.superview.frame = CGRectMake(100.f, 100.f, <width>, <height>); 
}

更改ModalViewController的位置和界限不需要更多。