5

Ich möchte ein modales UIViewController mit einem benutzerdefinierten Rahmen in iPad zeigen, zentriert auf seinem übergeordneten Ansichtscontroller.Show modal view controller mit benutzerdefiniertem Rahmen in iPad

Ich habe versucht, ein Formular zu verwenden, aber soweit ich weiß, kann der Rahmen und Schatteneffekt nicht geändert werden.

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

Ich habe auch versucht eine popover verwenden, aber soweit ich weiß, entweder ich kann es nicht zentriert oder ich den Pfeil nicht verbergen kann.

Gibt es eine andere Möglichkeit, Modal View-Controller anzuzeigen? Ist es möglich, dieses Problem mit Hilfe von Formblättern oder Popovers zu lösen?

+1

Mit presentPopoverFromRect können Sie ein Popover anzeigen, wo immer Sie wollen, und es sogar modal verhalten lassen, aber nur den Nachteil, dass der Pfeil nicht versteckt werden kann. – Anna

Antwort

4

Es gibt keine offizielle Möglichkeit, dies zu tun, aber Sie das gewünschte Verhalten durch eine benutzerdefinierte Ansicht zu schreiben, die einen Verweis oder delegieren hält bekommen können mit seinen Presenting-View-Controller zu interagieren und sie zu der Ansicht Hierarchie hinzufügen. Um das modale Gefühl wirklich zu erhalten, können Sie auch eine transparente Überlagerung über den präsentierenden Controller direkt unterhalb Ihrer 'modalen' Ansicht platzieren. Ich habe dies in einer Reihe von Apps getan und es funktioniert normalerweise großartig. Sie müssen wahrscheinlich die benutzerdefinierte Überlagerungsansicht erstellen, um Berührungen abzufangen und die Präsentation eleganter zu animieren.

Mein transparentes Overlay ist in der Regel etwas wie folgt aus:

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

Meine benutzerdefinierte modale Ansicht ist in der Regel etwas wie folgt aus:

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

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

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

In meinem Presenting-View-Controller würde ich in der Regel folgendes tun:

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

Die Delegaten für die beiden Klassen definiert gibt mir ziemlich viel offenen Zugang, um meinen präsentierenden Controller sowie meine Präsentation und Entlassung wie gewünscht zu manipulieren. Der einzige Nachteil besteht darin, dass es in einer Ansicht mit einer Navigationsleiste verwendet wird, da die Grenzen der Darstellung des präsentierenden Controllers die Grenzen der Navigationsleiste nicht für die Interaktion offen lassen, es gibt Möglichkeiten, dies zu umgehen, aber nicht von ihnen sind sehr hübsch (das Hinzufügen zur Ansicht des Navigationscontrollers ist eine Option).

+0

Was ist der Zweck von '- (void) performSelectorOnDelegate: (SEL) Selektor;' in der 'ModalViewDelegate'? –

1

Dies kann Ihre Frage nicht vollständig beantworten. Aber ich rufe den folgenden Code von einem rightbuttonitem auf einem Navigationscontroller auf, den ich zuvor oben in einer Detailansicht eines Splitview-Controllers platziert habe.

Diese modale Ansicht deckt den gesamten Bildschirm ab. Wollte man beispielsweise die Detailansicht nur dann abdecken, wenn sie im Detailansicht-Controller aufgerufen wird?

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

} 
6

Ich verwende die folgende Methode, um einen Modalansicht-Controller mit beliebiger Größe auf dem Bildschirm zu zentrieren. Sie können es im Center-View-Controller ändern, wenn Sie möchten. Dies funktioniert vom Storyboard, so dass Sie vielleicht stattdessen den View-Controller als Argument senden können. Aber abgesehen davon tut es, was Sie brauchen.

HINWEIS: Ich habe festgestellt, dass wenn Sie versuchen, ein anderes Modal über dieses zu zeigen, es auf die ursprüngliche Größe zurückkehrt.

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

Wenn es das einzige, was wollen Sie es funktioniert gut. Aber was ich gefunden habe, ist, dass Apples Implementierung von Modal View-Controllern ein wenig kontraproduktiv ist, da Sie nicht auf die darunter liegenden Teile zugreifen können und Sie sie nicht vollständig animieren können. Nützlich, wenn Sie eigene Übergänge haben möchten.

Und es fällt auch nicht in die Kategorie eines Kind View Controller, wie es über alle anderen Ansichten im Fenster steht.

+0

Das hat mir sehr geholfen. Vielen Dank. –

+0

+1 Ich habe versucht, die Mods seit Ewigkeiten zu skalieren, aber keine der Lösungen in StackOverflow war hilfreich. Es hat die View nicht korrekt skaliert/zentriert oder es hat nicht mit allen transitionStyles funktioniert. Diese Lösung ist perfekt! –

+0

IOS 7 Update unten und es kann das Kind lawn vc Problem oben erwähnt – gjpc

1

Ich ziehe fabio-Oliveiras Antwort, aber es erfordert eine gewisse Anpassung, damit es auf IOS 7 Multi-Thread-Umgebung arbeiten:

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

nun die Zentrierung Code in dem Ziel VC platzieren, so der neue Faden macht die Arbeit :

- (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 Ja, wenn Sie die schöne IOS 5 iPad 1en unterstützen, müssen Sie das Ziel vc drehen lassen:

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

hi @gjpc, Ich habe Ihren Code verwendet und es funktioniert gut, aber wenn es erscheint, ich meine, wenn das ModalView präsentiert wird, öffnet es sich von der Ecke und es entlässt in Richtung Zentrum. Hast du das gefunden? – Ranjit

+0

@Ranjit Ich benutze und ModalTransitionStyle: UIModalTransitionStyleCoverVertical]; und sie erscheinen von unten und verlassen durch den Boden – gjpc

+0

Ich versuchte mit ModalTransitionStyle: UIModalTransitionStyleCoverVertical] ;, aber das modale erscheint von unteren Ecke und wenn ich entlassen es entlässt in der Mitte des unteren. – Ranjit

1

In meinem Fall hat das Überschreiben viewWillLayoutSubviews den Trick gemacht.

- (void)viewWillLayoutSubviews { 
     [super viewWillLayoutSubviews]; 

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

Nichts mehr war nötig, um die Position und Grenzen der ModalViewController zu ändern.

+0

Dies funktionierte für mich, bis die Benutzeraktivität die iPad-Tastatur auf den Bildschirm brachte, zu welchem ​​Zeitpunkt das Modal zurück in seine vorherige Position zurückging. –