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

发布于 2024-09-30 05:02:34 字数 342 浏览 7 评论 0原文

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

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

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

我也尝试过使用弹出框,但据我所知,要么无法将其居中,要么无法隐藏箭头。

还有另一种方式来显示模态视图控制器吗?是否可以通过使用表单或弹出窗口来解决这个问题?

I want to show a modal UIViewController with a custom frame in iPad, centered on top of its parent view controller.

I tried using a form sheet but as far I know the frame and shadow effect can't be changed.

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

I also tried using a popover but as far as I know either I can't center it or I can't hide the arrow.

Is there another way to show modal view controllers? Is it possible to solve this problem by using form sheets or popovers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梓梦 2024-10-07 05:02:35

我使用以下方法创建一个模态视图控制器,其任何给定尺寸都位于屏幕中心。如果需要,您可以将其更改为在父视图控制器中居中。
这是在故事板中工作的,因此您也许可以将视图控制器作为参数发送。但除此之外它还能满足您的需要。

注意:我发现如果您尝试在这个模态上显示另一个模态,它会返回到原始大小。

- (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;
}

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

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

I'm using the following method to create a modal view controller with any given size centered in the screen. You may change it to center in the parent view controller if you want.
This is working from storyboard so you maybe can send the view controller as an argument instead. But apart from that it does what you need.

NOTE: I've found that if you try to show another modal over this one it will return to the original size.

- (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;
}

If it's the only thing you want it works fine.
But what I've found is that Apple's implementation of modal view controllers is a little counter productive as you cannot access any of it's underlying parts and so you cannot fully animate them. Useful if you want to have your own transitions.

And it doesn't fall also in the category of a child view controller as it stands over all the other views in the window.

花海 2024-10-07 05:02:35

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

我的透明覆盖通常是这样的:

@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]; 
}

使用在两个类上定义的委托为我提供了几乎开放的访问权限来操作我的呈现控制器以及我所希望的演示和解散。唯一的缺点是当它用在带有导航栏的视图上时,由于呈现控制器视图的边界将不包含导航栏的边界,使其保持开放状态以供交互,有多种方法可以解决此问题,但不是其中之一非常漂亮(添加到导航控制器的视图是一种选择)。

There is no official way to do this however you can get the desired behavior by writing a custom view which keeps a reference or delegate to interact with its presenting view controller and adding it to the view hierarchy. To really get the modal feel you can also place a transparent overlay over the presenting controller just below your 'modal' view. I have done this in a number of apps and it usually works out great. You will likely need to make the custom overlay view so you can intercept touches and more elegantly animate its presentation.

My transparent overlay is usually something like this:

@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;

My custom modal view is usually something like this:

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

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

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

In my presenting view controller I would usually do the following :

- (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]; 
}

Using the delegates defined on the two classes gives me pretty much open access to manipulate my presenting controller as well as my presentation and dismissal as desired. The only downside to this is when it is used on a view with a NavigationBar, as the bounds of the presenting controller's view will not contain the bounds of the NavigationBar leaving it open for interaction, there are ways to get around this but not of them are very pretty (adding to the navigation controller's view is one option).

波浪屿的海角声 2024-10-07 05:02:35

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

该模式视图覆盖整个屏幕。例如,您是否想仅在详细视图控制器中调用时才覆盖详细视图?

- (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];

}

This may not totally answer your question. But I call the following code from a rightbuttonitem on a navigation controller that I previously placed at the top of a detail view of a splitviewcontroller.

This modal view covers the whole screen. Did you want to cover, for example, the detail view only if called in the 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];

}
焚却相思 2024-10-07 05:02:35

我更喜欢 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;
}

I prefer fabio-oliveira's answer but it requires some adjustment to allow it to work on IOS 7's multi thread environment:

- (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;
}

Now place the centering code in the target VC so the new thread does the work:

- (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);
}

Oh Yes, if you are supporting those lovely IOS 5 iPad 1's, be sure to let the target vc rotate:

- (BOOL)shouldAutorotateToInterfaceOrientation:
                         (UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}
少钕鈤記 2024-10-07 05:02:35

就我而言,重写 viewWillLayoutSubviews 就可以了。

- (void)viewWillLayoutSubviews {
        [super viewWillLayoutSubviews];

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

无需再更改 ModalViewController 的位置和边界。

In my case, overriding viewWillLayoutSubviews did the trick.

- (void)viewWillLayoutSubviews {
        [super viewWillLayoutSubviews];

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

Nothing more was needed to change the position and bounds of ModalViewController.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文