Ich mache gerade eine App, die mehrere Timer haben wird, die im Grunde alle gleich sind.
Ich möchte eine benutzerdefinierte Klasse erstellen, die den gesamten Code für die Timer sowie das Layout / die Animationen verwendet, damit ich 5 identische Timer haben kann, die unabhängig voneinander arbeiten.
Ich habe das Layout mit IB (xcode 4.2) erstellt und der gesamte Code für die Timer befindet sich derzeit nur in der Viewcontroller-Klasse.
Ich habe Schwierigkeiten, mein Gehirn darum zu wickeln, wie man alles in eine benutzerdefinierte Klasse kapselt und es dann dem Viewcontroller hinzufügt. Jede Hilfe wäre sehr dankbar.
UITableViewCell
oder verwendenUICollectionViewCell
. In meinem Fall benötige ich eine kleine, aber ziemlich komplexe Ansicht, die ich in Controllern und Sammlungsansichten häufig verwenden kann. Und die Designer überarbeiten es ständig, daher möchte ich einen einzigen Ort, an dem das Layout definiert wird. Daher eine Feder.Antworten:
Um konzeptionell zu antworten, sollte Ihr Timer wahrscheinlich eine Unterklasse von
UIView
statt seinNSObject
.Um eine Instanz Ihres Timers in IB zu instanziieren, ziehen Sie sie einfach
UIView
in die Ansicht Ihres View Controllers und setzen Sie ihre Klasse auf den Klassennamen Ihres Timers.Denken Sie an
#import
Ihre Timer-Klasse in Ihrem View Controller.Bearbeiten: für IB-Design (Code-Instanziierung siehe Revisionsverlauf)
Ich bin mit Storyboard überhaupt nicht sehr vertraut, aber ich weiß, dass Sie Ihre Schnittstelle in IB mithilfe einer
.xib
Datei erstellen können, die fast identisch mit der Verwendung der Storyboard-Version ist. Sie sollten sogar in der Lage sein, Ihre Ansichten als Ganzes von Ihrer vorhandenen Oberfläche in die.xib
Datei zu kopieren und einzufügen .Um dies zu testen, habe ich ein neues
.xib
Leerzeichen mit dem Namen "MyCustomTimerView.xib" erstellt. Dann habe ich eine Ansicht hinzugefügt und dazu eine Beschriftung und zwei Schaltflächen hinzugefügt. Gefällt mir So:Ich habe eine neue Ziel-C-Klasse-Unterklasse mit dem
UIView
Namen "MyCustomTimer" erstellt. In meinem.xib
habe ich die Owner- Klasse meiner Datei auf MyCustomTimer festgelegt . Jetzt kann ich Aktionen und Ausgänge wie jede andere Ansicht / Steuerung verbinden. Die resultierende.h
Datei sieht folgendermaßen aus:Die einzige Hürde, die noch zu springen ist, besteht darin, dies
.xib
in meineUIView
Unterklasse aufzunehmen. Durch die Verwendung eines.xib
wird das erforderliche Setup drastisch reduziert. Und da Sie Storyboards zum Laden der Timer verwenden, wissen wir, dass dies-(id)initWithCoder:
der einzige Initialisierer ist, der aufgerufen wird. So sieht die Implementierungsdatei aus:Die genannte Methode
loadNibNamed:owner:options:
macht genau das, wonach es sich anhört. Es lädt die Schreibfeder und setzt die Eigenschaft "File's Owner" auf self. Wir extrahieren das erste Objekt im Array und das ist die Stammansicht der Feder. Wir fügen die Ansicht als Unteransicht hinzu und Voila wird auf dem Bildschirm angezeigt.Natürlich ändert dies nur die Hintergrundfarbe des Etiketts, wenn die Tasten gedrückt werden, aber dieses Beispiel sollte Sie auf Ihrem Weg gut machen.
Anmerkungen basierend auf Kommentaren:
Es ist erwähnenswert, dass Sie bei unendlichen Rekursionsproblemen wahrscheinlich den subtilen Trick dieser Lösung verpasst haben. Es macht nicht das, was du denkst. Die Ansicht, die in das Storyboard eingefügt wird, wird nicht angezeigt, sondern lädt eine andere Ansicht als Unteransicht. Diese Ansicht, die es lädt, ist die Ansicht, die in der Feder definiert ist. Der "Eigentümer der Datei" in der Schreibfeder ist diese unsichtbare Ansicht. Der coole Teil ist, dass diese unsichtbare Ansicht immer noch eine Objective-C-Klasse ist, die als eine Art Ansichts-Controller für die Ansicht verwendet werden kann, die sie von der Schreibfeder einbringt. Zum Beispiel sind die
IBAction
Methoden in derMyCustomTimer
Klasse etwas, das Sie in einem Ansichts-Controller mehr erwarten würden als in einer Ansicht.Als Randnotiz können einige argumentieren, dass dies bricht
MVC
und ich stimme etwas zu. Aus meiner Sicht ist es enger mit einem Brauch verbundenUITableViewCell
, der manchmal auch Teilesteuerung sein muss.Es ist auch erwähnenswert, dass diese Antwort eine sehr spezifische Lösung bieten sollte; Erstellen Sie eine Feder, die in derselben Ansicht wie in einem Storyboard mehrfach instanziiert werden kann . Sie können sich beispielsweise leicht vorstellen, dass sechs dieser Timer gleichzeitig auf einem iPad-Bildschirm angezeigt werden. Wenn Sie nur eine Ansicht für einen Ansichtscontroller angeben müssen, der in Ihrer Anwendung mehrmals verwendet werden soll, ist die von jyavenard für diese Frage bereitgestellte Lösung mit ziemlicher Sicherheit eine bessere Lösung für Sie.
quelle
userInfo
Eigenschaft für die Benachrichtigung@property(nonatomic,copy) NSDictionary *userInfo;
File's Owner
Ihr Klassenname festgelegt ist, ist mein Problem mit der unendlichen Rekursion gelöst.[self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"MyCustomTimerView" owner:self options:nil] objectAtIndex:0]];
Hinzufügen der zweiten UIView ... Das sieht für mich irgendwie komisch aus. Niemand sonst fühlt sich genauso? Wenn ja, ist dies etwas Apfel von Design gemacht? Oder ist die Lösung jemand, der dies findet?Schnelles Beispiel
Aktualisiert für Xcode 10 und Swift 4
Hier ist ein grundlegender Spaziergang durch. Ich habe ursprünglich viel davon gelernt, als ich mir diese Youtube-Videoserie angesehen habe . Später habe ich meine Antwort basierend auf diesem Artikel aktualisiert .
Fügen Sie benutzerdefinierte Ansichtsdateien hinzu
Die folgenden zwei Dateien bilden Ihre benutzerdefinierte Ansicht:
UIView
UnterklasseDie Details zum Hinzufügen sind unten.
Xib-Datei
Fügen Sie Ihrem Projekt eine .xib-Datei hinzu (Datei> Neu> Datei ...> Benutzeroberfläche> Ansicht) . Ich rufe meine an
ReusableCustomView.xib
.Erstellen Sie das Layout, das Ihre benutzerdefinierte Ansicht haben soll. Als Beispiel werde ich ein Layout mit a
UILabel
und a erstellenUIButton
. Es ist eine gute Idee, das automatische Layout zu verwenden, damit die Größe automatisch geändert wird, unabhängig davon, auf welche Größe Sie sie später einstellen. (Ich habe Freeform für die xib-Größe im Attributinspektor verwendet, damit ich die simulierten Metriken anpassen kann, dies ist jedoch nicht erforderlich.)Schnelle Datei
Fügen Sie Ihrem Projekt eine .swift-Datei hinzu (Datei> Neu> Datei ...> Quelle> Swift-Datei) . Es ist eine Unterklasse von
UIView
und ich rufe meine anReusableCustomView.swift
.Machen Sie die Swift-Datei zum Eigentümer
Gehen Sie zurück zu Ihrer .xib-Datei und klicken Sie in der Dokumentübersicht auf " Dateibesitzer ". Schreiben Sie im Identitätsinspektor den Namen Ihrer .swift-Datei als benutzerdefinierten Klassennamen.
Fügen Sie einen benutzerdefinierten Ansichtscode hinzu
Ersetzen Sie den
ReusableCustomView.swift
Inhalt der Datei durch den folgenden Code:Stellen Sie sicher, dass die Schreibweise für den Namen Ihrer .xib-Datei richtig ist.
Schließen Sie die Steckdosen und Aktionen an
Schließen Sie die Steckdosen und Aktionen an, indem Sie das Ziehen von der Beschriftung und der Schaltfläche im xib-Layout zum schnellen benutzerdefinierten Ansichtscode steuern.
Verwenden Sie Ihre benutzerdefinierte Ansicht
Ihre benutzerdefinierte Ansicht ist jetzt fertig. Alles, was Sie tun müssen, ist, ein
UIView
beliebiges Element in Ihr Haupt-Storyboard einzufügen. Setzen Sie den Klassennamen der AnsichtReusableCustomView
im Identitätsinspektor auf.quelle
Bundle.main
zuBundle(for: ...)
den Trick macht. AnscheinendBundle.main
ist zur Entwurfszeit nicht verfügbar.init(frame:)
. Sobald Sie dies hinzugefügt haben (und den gesamten Initialisierungscode in einecommonInit()
Funktion gezogen haben), funktioniert es einwandfrei und wird in IB angezeigt. Weitere Informationen finden Sie hier: stackoverflow.com/questions/31265906/…Antwort für Ansichts-Controller, nicht für Ansichten :
Es gibt eine einfachere Möglichkeit, eine XIB aus einem Storyboard zu laden. Angenommen, Ihr Controller ist vom Typ MyClassController, von dem erbt
UIViewController
.Sie fügen
UIViewController
Ihrem Storyboard einen using IB hinzu. Ändern Sie den Klassentyp in MyClassController. Löschen Sie die Ansicht, die automatisch im Storyboard hinzugefügt wurde.Stellen Sie sicher, dass die gewünschte XIB MyClassController.xib heißt.
Wenn die Klasse während des Ladens des Storyboards instanziiert wird, wird die xib automatisch geladen. Der Grund dafür liegt in der Standardimplementierung, bei
UIViewController
der die XIB mit dem Klassennamen aufgerufen wird.quelle
'Could not load NIB in bundle: 'NSBundle </Users/me/.../MyAppName.app> (loaded)' with name 'uB0-aR-WjG-view-4OA-9v-tyV''
. Beachten Sie den whacko nibName. Ich verwende den richtigen Klassennamen für die in der Feder.Dies ist keine wirkliche Antwort, aber ich denke, es ist hilfreich, diesen Ansatz zu teilen.
Ziel c
Schnell
Optional :
Jetzt können Sie Ihre benutzerdefinierte Ansicht in Ihr Storyboard einfügen und sie wird angezeigt :)
CustomViewWithXib.h :
CustomViewWithXib.m :
CustomViewWithXib.swift :
Hier finden Sie einige Beispiele finden Sie hier .
Hoffentlich hilft das.
quelle