ios 在 iPad 中显示带有自定义框架的模态视图控制器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4065918/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Show modal view controller with custom frame in iPad
提问by hpique
I want to show a modal UIViewController
with a custom frame in iPad, centered on top of its parent view controller.
我想UIViewController
在 iPad 中显示一个带有自定义框架的模式,以其父视图控制器的顶部为中心。
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?
还有另一种方式来显示模态视图控制器吗?是否可以通过使用表单或弹出框来解决此问题?
采纳答案by RLB
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).
使用在这两个类上定义的委托让我可以非常开放地操作我的呈现控制器以及我的呈现和按需解除。唯一的缺点是当它在带有 NavigationBar 的视图上使用时,因为呈现控制器视图的边界将不包含 NavigationBar 的边界,使其开放进行交互,有办法解决这个问题,但不是他们非常漂亮(添加到导航控制器的视图是一种选择)。
回答by Fábio Oliveira
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.
如果它是您唯一想要的,它就可以正常工作。但是我发现 Apple 的模态视图控制器的实现有点适得其反,因为您无法访问它的任何底层部件,因此您无法完全为它们设置动画。如果您想拥有自己的过渡,则很有用。
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.
它也不属于子视图控制器的范畴,因为它位于窗口中的所有其他视图之上。
回答by cliff
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.
这可能无法完全回答您的问题。但是我从导航控制器上的 rightbuttonitem 调用以下代码,我之前放置在 splitviewcontroller 的详细视图顶部。
This modal view covers the whole screen. Did you want to cover, for example, the detail view only if called in the detailviewcontroller?
这个模态视图覆盖了整个屏幕。例如,您是否想仅在 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];
}
回答by gjpc
I prefer fabio-oliveira's answer but it requires some adjustment to allow it to work on IOS 7's multi thread environment:
我更喜欢 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;
}
Now place the centering code in the target VC so the new thread does the work:
现在将居中代码放在目标 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);
}
Oh Yes, if you are supporting those lovely IOS 5 iPad 1's, be sure to let the target vc rotate:
哦对了,如果你正在支持那些可爱的 IOS 5 iPad 1,一定要让目标 vc 旋转:
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
回答by nefarianblack
In my case, overriding viewWillLayoutSubviews
did the trick.
就我而言,覆盖viewWillLayoutSubviews
成功了。
- (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
.
无需再更改 的位置和边界ModalViewController
。