So fügen Sie die Ansicht eines UIViewControllers als Unteransicht hinzu

75

Hinweis für Googler: Diese Qualitätssicherung ist jetzt sechs Jahre veraltet !

Wie Micky unten und andere erwähnen, geschieht dies jetzt täglich mit Containern in iOS.


Ich habe einen ViewController, der viele Unteransichten steuert. Wenn ich auf eine der Schaltflächen klicke, initialisiere ich einen anderen Ansichtscontroller und zeige seine Ansicht als Unteransicht dieser Ansicht an. Die Unteransicht überschreitet jedoch die Grenzen des Rahmens für die Unteransicht und füllt den gesamten Bildschirm aus.

Was könnte falsch sein? Ich gehe davon aus, dass das Problem darin besteht, dass die Ansicht von UIViewController einen Rahmen (0,0,320,460) hat und somit den gesamten Bildschirm ausfüllt (obwohl Berührungsereignisse nur empfangen werden, wenn sie innerhalb der Rahmengrenzen der Unteransicht berührt werden). Wie kann ich die Größe des Rahmens so ändern, dass er als Unteransicht passt?

Kurz gesagt, ich benötige Hilfe beim Hinzufügen der Ansicht eines Viewcontrollers als Unteransicht zur Ansicht eines anderen Viewcontrollers.

Vielen Dank!

sperumal
quelle
1
Ich würde dagegen empfehlen. Ich habe dies für meine erste iPhone-App getan und es stellte sich als großes bizarres Durcheinander heraus, ganz zu schweigen von der Tatsache, dass es eine Menge Dinge kaputt machte, die ich mit Interface Builder machen wollte. In den 3.0-Dokumenten heißt es ausdrücklich: 1 View Controller pro Bildschirm. Du solltest das tun!
bpapa
Ja, sogar ich habe darüber gelesen, aber das Problem ist, wenn ich alles in einen Viewcontroller stecke, ist es eine ganze Menge Code in einem, und es gibt viele IBOutlets und Aktionen und Tabellen. Aus Gründen der Klarheit und Modularität habe ich daher versucht, zwei separate Viewcontroller zu haben, wobei der zweite nur den Haupt-Viewcontroller mit View versorgt und seine eigenen Ereignisse behandelt. Auf diese Weise ist der Hauptansichtscontroller etwas sauberer. Was soll ich stattdessen tun? Sollte ich mehrere View Controller mit Navi Controller oder 1 riesigen View Controller haben?
Sperumal
Schauen Sie sich dieses Tutorial an . Es funktioniert jedoch nur teilweise
Casebash

Antworten:

86

Ab iOS 5 können Sie mit Apple jetzt benutzerdefinierte Container erstellen , um einen UIViewController zu einem anderen UIViewController hinzuzufügen, insbesondere über Methoden wie addChildViewController, sodass UIViewController tatsächlich verschachtelt werden können

BEARBEITEN: Inklusive In-Place-Zusammenfassung, um Verbindungsbruch zu vermeiden

Ich zitiere:

iOS bietet viele Standardcontainer, mit denen Sie Ihre Apps organisieren können. Manchmal müssen Sie jedoch einen benutzerdefinierten Workflow erstellen, der nicht mit dem von einem der Systemcontainer bereitgestellten übereinstimmt. Möglicherweise benötigt Ihre App in Ihrer Vision eine bestimmte Organisation von untergeordneten Ansichtssteuerungen mit speziellen Navigationsgesten oder Animationsübergängen zwischen ihnen. Dazu implementieren Sie einen benutzerdefinierten Container - Erzählen Sie mir mehr ...

...und:

Wenn Sie einen Container entwerfen, erstellen Sie explizite Eltern-Kind - Beziehungen zwischen Ihrem Container, der Mutter und andere Ansicht - Controller, seine Kinder - Sagen Sie mir mehr

Beispiel (mit freundlicher Genehmigung von Apple Docs) Hinzufügen der Ansicht eines anderen Ansichtscontrollers zur Ansichtshierarchie des Containers

- (void) displayContentController: (UIViewController*) content
{
   [self addChildViewController:content];                 
   content.view.frame = [self frameForContentController]; 
   [self.view addSubview:self.currentClientView];
   [content didMoveToParentViewController:self];          
}
MickyD
quelle
2
Ich habe oben in meiner Antwort einen Kommentar dazu hinzugefügt.
Steven Fisher
Sind Sie sicher, dass dies iOS 5 ist? Ich bekomme Abstürze mit iOS 5, aber es funktioniert gut in iOS 6.
Steven Fisher
iOS 5, wir verwenden es in unserer App
MickyD
Danke Micky. Es stellt sich heraus, dass es nur das Storyboard-Embed-Segment ist, das in iOS 5 nicht unterstützt wird.
Steven Fisher
3
Was ist die Rolle von currentClientView? Ich kann es in der Dokumentation überhaupt nicht verstehen.
Iulian Onofrei
41

Dank dieser Jungs habe ich es geschafft http://highoncoding.com/Articles/848_Creating_iPad_Dashboard_Using_UIViewController_Containment.aspx

Fügen Sie UIView hinzu und verbinden Sie es mit dem Header:

@property (weak, nonatomic) IBOutlet UIView *addViewToAddPlot;

In - (void) viewDidLoad tun Sie Folgendes:

ViewControllerToAdd *nonSystemsController = [[ViewControllerToAdd alloc] initWithNibName:@"ViewControllerToAdd" bundle:nil];
    nonSystemsController.view.frame = self.addViewToAddPlot.bounds;
    [self.addViewToAddPlot addSubview:nonSystemsController.view];
    [self addChildViewController:nonSystemsController];
    [nonSystemsController didMoveToParentViewController:self];

Genießen

Naloiko Eugene
quelle
3
In der Dokumentation heißt es, dass didMoveToParentViewController nach addChildViewController aufgerufen werden sollte, nicht vorher.
Aaron
Danke ... tolle Lösung!
Jalopezsuarez
26

Diese Antwort ist für alte Versionen von iOS korrekt, aber veraltet. Sie sollten die Antwort von Micky Duncan verwenden, die benutzerdefinierte Container abdeckt.

Tu das nicht! Die Absicht des UIViewControllerist es, den gesamten Bildschirm zu steuern. Es ist einfach nicht dafür geeignet und es fügt nicht wirklich etwas hinzu, was Sie brauchen.

Sie benötigen lediglich ein Objekt, dem Ihre benutzerdefinierte Ansicht gehört. Verwenden Sie einfach eine Unterklasse vonUIView selbst, damit sie Ihrer Fensterhierarchie hinzugefügt werden kann und die Speicherverwaltung vollautomatisch erfolgt.

Zeigen Sie dem Eigentümer der Unteransicht NIB auf eine benutzerdefinierte Unterklasse von UIView. Fügen Sie contentViewdieser benutzerdefinierten Unterklasse eine Steckdose hinzu und richten Sie sie auf die Ansicht innerhalb der Feder. Führen Sie in der benutzerdefinierten Unterklasse Folgendes aus:

- (id)initWithFrame: (CGRect)inFrame;
{
    if ( (self = [super initWithFrame: inFrame]) ) {
        [[NSBundle mainBundle] loadNibNamed: @"NibNameHere"
                                      owner: self
                                    options: nil];
        contentView.size = inFrame.size;
        // do extra loading here
        [self addSubview: contentView];
    }
    return self;
}

- (void)dealloc;
{
    self.contentView = nil;
    // additional release here
    [super dealloc];
}

(Ich gehe davon aus, dass Sie hier initWithFrame:die Unteransicht erstellen.)

Steven Fisher
quelle
2
Obwohl dies zu dieser Zeit eine recht gute Antwort war, ist dies möglicherweise eine veraltete Philosophie seit iOS 5. Siehe meine Antwort unten
MickyD
1
In der Tat wurde dies vor Jahren geschrieben. Ich habe noch keine benutzerdefinierten Container verwendet, aber das scheint der richtige Weg zu sein, um dies zu lösen.
Steven Fisher
Danke für den Stecker zu meiner Antwort Steven :)
MickyD
17

Ich bin der Meinung, dass alle diese Antworten etwas unvollständig sind. Hier ist der richtige Weg, um die Ansicht eines viewControllers als Unteransicht einer anderen viewController-Ansicht hinzuzufügen:

    [self addChildViewController:viewControllerToAdd];
    [self.view addSubview:viewControllerToAdd.view];
    [viewControllerToAdd didMoveToParentViewController:self];

Wenn Sie möchten, können Sie dies als Snippet in Ihren Code kopieren. SO scheint die Formatierung von Code-Ersetzungen nicht zu verstehen, aber sie werden in Xcode sauber angezeigt:

    [self addChildViewController:<#viewControllerToAdd#>];
    [self.view addSubview:<#viewControllerToAdd#>.view];
    [<#viewControllerToAdd#> didMoveToParentViewController:self];

wird sich bewegen wird automatisch mit addChild aufgerufen. Danke @iOSSergey

Wenn Ihr benutzerdefinierter Container die Methode addChildViewController: aufruft, ruft er automatisch die Methode willMoveToParentViewController: des Ansichtscontrollers auf, der als untergeordnetes Element hinzugefügt werden soll, bevor er hinzugefügt wird.

Logan
quelle
Wenn Ihr benutzerdefinierter Container die Methode addChildViewController: aufruft, ruft er automatisch die Methode willMoveToParentViewController: des Ansichtscontrollers auf, der als untergeordnetes Element hinzugefügt werden soll, bevor er hinzugefügt wird.
iOSergey
@iOSergey hast du einen Link dazu? Würde gerne die Antwort aktualisieren, um korrekter zu sein.
Logan
Eigentlich habe ich willMoveToParent immer auch manuell verwendet, aber als ich versehentlich den Apple-Verweis auf diese Funktion gelesen habe, war ich überrascht :) developer.apple.com/library/ios/documentation/UIKit/Reference/… :
iOSergey
@iOSergey - Entschuldigung, vielleicht bin ich dicht, aber ich sehe es dort nicht :) Ich möchte etwas genauer darauf hinweisen! Sie sind nicht allein, wenn Sie immer anrufen, und ich hätte gerne eine gute Referenz, wenn die Leute mir unweigerlich sagen, dass ich sie wieder einsetzen soll! Danke noch einmal!
Logan
Suchen Sie auf der von mir verlinkten Website nach "willMoveToParentViewController", geben Sie die Referenz "willMoveToParentViewController" aus und unter "Diskussion" den letzten Absatz :) Ich habe den vollständigen Link gepostet, aber aus irgendeinem Grund wird er nach oben umgeleitet.
iOSergey
6

Verwenden:

[self.view addSubview:obj.view];
rahul gupta
quelle
1

Ändern Sie die Rahmengröße von viewcontroller.view.frameund fügen Sie sie dann zur Unteransicht hinzu.[viewcontrollerparent.view addSubview:viewcontroller.view]

CiNN
quelle
Ich versuchte es. Es funktioniert nicht. Soll ich etwas im Interface Builder machen.
Sperumal
0

Sie müssen die Begrenzungseigenschaften so einstellen, dass sie zu diesem Rahmen passen. Rahmen seine Übersichtseigenschaften, und Grenzen begrenzen den Rahmen im Koordinatensystem der Ansicht selbst.

Bolek
quelle
0

Sie können PopupController für dasselbe SDK verwenden, das UIViewController als Unteransicht anzeigt. Sie können PopupController überprüfen

Hier ist ein Beispielcode dafür

popup = PopupController
        .create(self.navigationController!)
        .customize(
            [
                .layout(.center),
                .animation(.fadeIn),
                .backgroundStyle(.blackFilter(alpha: 0.8)),
                .dismissWhenTaps(true),
                .scrollable(true)
            ]
        )
        .didShowHandler { popup in
        }
        .didCloseHandler { popup in
    }
    let container = MTMPlayerAndCardSelectionVC.instance()
    container.closeHandler = {() in
        self.popup.dismiss()
    }

    popup.show(container)
Anjali Jariwala
quelle