J'essaie de faire quelque chose d'un peu élaboré, mais quelque chose qui devrait être possible. Voici donc un défi pour tous vos experts (ce forum est un pack de beaucoup d'entre vous :)).
Je crée un "composant" Questionnaire, que je veux charger sur un NavigationContoller
(mon QuestionManagerViewController
). Le "composant" est un "vide" UIViewController
, qui peut charger différentes vues en fonction de la question à laquelle il faut répondre.
La façon dont je le fais est:
- Créez l'objet Question1View en tant que
UIView
sous - classe, en définissant certainsIBOutlets
. - Créez (en utilisant Interface Builder) le
Question1View.xib
(ICI EST O IS MON PROBLÈME EST PROBABLEMENT ). J'ai défini leUIViewController
et leUIView
pour être de la classe Question1View. - Je relie les prises avec le composant de la vue (en utilisant IB).
Je remplace le
initWithNib
monQuestionManagerViewController
pour ressembler à ceci:- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) { // Custom initialization } return self; }
Lorsque j'exécute le code, j'obtiens cette erreur:
2009-05-14 15: 05: 37.152 iMobiDines [17148: 20b] *** Arrêt de l'application en raison d'une exception non interceptée '
NSInternalInconsistencyException
', raison: 'a-[UIViewController _loadViewFromNibNamed:bundle:]
chargé la plume "Question1View" mais la sortie de la vue n'a pas été définie.'
Je suis sûr qu'il existe un moyen de charger la vue à l'aide du fichier nib, sans avoir besoin de créer une classe viewController.
la source
Merci à tous. J'ai trouvé un moyen de faire ce que je voulais.
UIView
avec lesIBOutlet
s dont vous avez besoin.UIViewController
(pas de sous-classe personnalisée, mais la "vraie"). La vue du propriétaire du fichier est connectée à la vue principale et sa classe est déclarée comme celle de l'étape 1).IBOutlet
s.Le
DynamicViewController
peut exécuter sa logique pour décider quelle vue / xib charger. Une fois sa décision prise, dans laloadView
méthode, mettez quelque chose comme ceci:C'est tout!
La
loadNibNamed
méthode du bundle principal se chargera d'initialiser la vue et de créer les connexions.Le ViewController peut maintenant afficher une vue ou une autre en fonction des données en mémoire, et l'écran "parent" n'a plus besoin de s'embêter avec cette logique.
la source
Je ne sais pas de quoi parlent certaines des réponses, mais je dois mettre cette réponse ici lorsque je ferai une recherche dans Google la prochaine fois. Mots-clés: "Comment charger une UIView à partir d'une pointe" ou "Comment charger une UIView à partir d'un NSBundle".
Voici le code presque à 100% directement du livre Apress Beginning iPhone 3 (page 247, «Utilisation de la nouvelle cellule de vue de table»):
Cela suppose que vous ayez une
UIView
sous - classe appeléeBlah
, une nib appeléeBlah
qui contient unUIView
dont la classe est définie surBlah
.Catégorie: NSObject + LoadFromNib
Extension rapide
Et un exemple d'utilisation:
la source
isKindOf
vous êtes protégé des modifications de la structure du Bundle.assert
serait probablement une meilleure solution. De cette façon, vous ne masquerez que le problème.for
boucle. Il le complète.Pour tous ceux qui ont besoin de gérer plus d'une instance de la vue personnalisée, c'est-à-dire une collection de sorties, j'ai fusionné et personnalisé les réponses @Gonso, @AVeryDev et @Olie de cette manière:
Créez un personnalisé
MyView : UIView
et définissez-le comme " Classe personnalisée " de la racineUIView
dans le XIB souhaité ;Créez toutes les prises dont vous avez besoin
MyView
(faites-le maintenant car après le point 3, l'IB vous proposera de connecter les prises à laUIViewController
vue personnalisée et non à la vue personnalisée);Définissez votre en
UIViewController
tant que « propriétaire du fichier » de la vue personnalisée XIB ;Dans l'
UIViewController
ajout d'un nouveauUIViews
pour chaque instance deMyView
vous voulez, et connectez-les à laUIViewController
création d'une collection de sorties : ces vues agiront comme des vues «wrapper» pour les instances de vue personnalisées;Enfin, dans le
viewDidLoad
votreUIViewController
ajoutez les lignes suivantes:la source
J'utiliserais UINib pour instancier une UIView personnalisée à réutiliser
Les fichiers nécessaires dans ce cas sont MyCustomView.xib , MyCustomViewClass.h et MyCustomViewClass.m Notez que
[UINib instantiateWithOwner]
renvoie un tableau, vous devez donc utiliser l'élément qui reflète l'UIView que vous souhaitez réutiliser. Dans ce cas, c'est le premier élément.la source
Vous ne devez pas définir la classe de votre contrôleur de vue comme une sous-classe d'
UIView
Interface Builder. C'est certainement au moins une partie de votre problème. Laissez-le commeUIViewController
une sous-classe ou une autre classe personnalisée que vous avez.En ce qui concerne le chargement seulement une vue d'un xib, j'étais sous l'hypothèse que vous avait d'avoir une sorte de contrôleur de vue (même si elle ne dépasse pas
UIViewController
, ce qui peut être trop lourd pour vos besoins) ensemble en tant que propriétaire dans l' interface du fichier Builder si vous souhaitez l'utiliser pour définir votre interface. J'ai également fait quelques recherches pour le confirmer. En effet, sinon, il n'y aurait aucun moyen d'accéder à l'un des éléments d'interface dans leUIView
, ni aucun moyen de déclencher vos propres méthodes dans le code par des événements.Si vous utilisez un en
UIViewController
tant que propriétaire de votre fichier pour vos vues, vous pouvez simplement l'utiliserinitWithNibName:bundle:
pour le charger et récupérer l'objet du contrôleur de vue. Dans IB, assurez-vous de régler laview
sortie sur la vue avec votre interface dans le xib. Si vous utilisez un autre type d'objet en tant que propriétaire de votre fichier, vous devrez utiliserNSBundle
laloadNibNamed:owner:options:
méthode de pour charger la plume, en passant une instance du propriétaire du fichier à la méthode. Toutes ses propriétés seront définies correctement en fonction des prises que vous définissez dans IB.la source
Vous pouvez également utiliser initWithNibName de UIViewController au lieu de loadNibNamed. C'est plus simple, je trouve.
Il ne vous reste plus qu'à créer MySubView.xib et MySubView.h / m. Dans MySubView.xib, définissez la classe Propriétaire du fichier sur UIViewController et la classe d'affichage sur MySubView.
Vous pouvez positionner et dimensionner le
subview
à l'aide du fichier xib parent.la source
C'est une excellente question (+1) et les réponses ont été presque utiles;) Désolé les gars, mais j'ai eu un sacré temps à parcourir cela, bien que Gonso et AVeryDev aient donné de bons indices. Espérons que cette réponse aidera les autres.
MyVC
est le contrôleur de vue détenant tout cela.MySubview
est la vue que nous voulons charger à partir d'un xibMySubView
la bonne taille et de la bonne forme et positionnée où vous le souhaitez.Dans MyVC.h, ayez
Dans MyVC.m,
@synthesize mySubView;
et n'oubliez pas de le publierdealloc
.UIView *view
(peut être inutile, mais a fonctionné pour moi.) Synthétisez et libérez-le dans .mMySubview
et liez la propriété view à votre vue.IBOutlet
que vous souhaitezDe retour dans MyVC.m, ayez
Le plus difficile pour moi était: les indices dans les autres réponses chargeaient ma vue depuis le xib, mais ne remplaçaient PAS la vue dans MyVC (duh!) - J'ai dû échanger cela par moi-même.
De plus, pour accéder aux
mySubview
méthodes de, laview
propriété du fichier .xib doit être définie surMySubview
. Sinon, il revient comme un vieuxUIView
.S'il y avait un moyen de charger
mySubview
directement à partir de son propre xib, ça basculerait, mais cela m'a amené là où je devais être.la source
C'est quelque chose qui devrait être plus facile. J'ai fini par étendre
UIViewController
et ajouter unloadNib:inPlaceholder:
sélecteur. Maintenant je peux direVoici le code de la catégorie (il fait le même rigamarole comme décrit par Gonso):
la source
En rapide
En fait, ma résolution de ce problème était de charger la vue dans un viewDidLoad dans mon CustonViewController où je voulais utiliser la vue comme ça:
Ne chargez pas la vue dans une
loadView()
méthode! La méthode loadView sert à charger la vue de votre ViewController personnalisé.la source
Moi aussi, je voulais faire quelque chose de similaire, voici ce que j'ai trouvé: (SDK 3.1.3)
J'ai un contrôleur de vue A (lui-même détenu par un contrôleur Nav) qui charge VC B sur une pression de bouton:
Dans AViewController.m
Maintenant, VC B a son interface de Bnib, mais quand un bouton est enfoncé, je veux aller dans un "mode d'édition" qui a une interface utilisateur distincte d'une autre pointe, mais je ne veux pas de nouveau VC pour le mode d'édition, Je veux que la nouvelle pointe soit associée à mon B VC existant.
Donc, dans BViewController.m (dans la méthode de pression de bouton)
Ensuite, sur un autre bouton, appuyez sur (pour quitter le mode édition):
et je suis de retour à mon Bnib d'origine.
Cela fonctionne bien, mais notez que mon EditMode.nib n'a qu'un seul obj de niveau supérieur, un obj UIView. Peu importe que le propriétaire du fichier dans cette pointe soit défini comme BViewController ou NSObject par défaut, MAIS assurez-vous que la sortie d'affichage dans le propriétaire du fichier n'est PAS définie sur quoi que ce soit. Si c'est le cas, j'obtiens un crash exc_bad_access et xcode procède au chargement de 6677 trames de pile montrant une méthode UIView interne appelée à plusieurs reprises ... ressemble donc à une boucle infinie. (Le View Outlet EST défini dans mon Bnib d'origine cependant)
J'espère que cela t'aides.
la source
J'ai fait une catégorie que j'aime:
UIView+NibInitializer.h
UIView+NibInitializer.m
Ensuite, appelez comme ceci:
Utilisez un nom de plume si votre plume est nommée autre chose que le nom de votre classe.
Pour le remplacer dans vos sous-classes pour un comportement supplémentaire, il pourrait ressembler à ceci:
la source
Pour les utilisateurs de Swift avec option personnalisable:
UIView
sous - classe personnalisée et un fichier xib , que nous nommerons d'après notre propre nom de classe: dans notre cas MemeView. Dans la classe Meme View, n'oubliez pas de la définir comme pouvant être conçue avec le@IBDesignable
attribut avant la déclaration de classeN'oubliez pas de définir le propriétaire du fichier dans le xib avec notre
UIView
sous-classe personnalisée dans le panneau Inspecteur d'indétitéDans le fichier xib, nous pouvons maintenant construire notre interface, créer des contraintes, créer des débouchés, des actions, etc.
Nous devons implémenter quelques méthodes dans notre classe personnalisée pour ouvrir le xib une fois initialisé
class XibbedView: UIView {
}
Dans notre classe personnalisée, nous pouvons également définir certaines propriétés pouvant être inspectées pour avoir un contrôle total sur celles-ci à partir du générateur d'interface
@IBDesignable class MemeView: XibbedView {
}
Quelques exemples:
Si nous devons ajouter plus d'informations pendant que la vue est affichée dans un storyboard ou un autre xib, pour ce faire, nous pouvons l'implémenter
prepareForInterfaceBuilder()
, cette méthode sera exécutée uniquement lors de l'ouverture du fichier dans le générateur d'interface. Si vous avez fait tout ce que j'ai écrit mais que rien ne fonctionne, c'est un moyen de déboguer une vue sigle en ajoutant des points d'arrêt dans sa mise en œuvre. Voici la hiérarchie des vues.J'espère que cela aide un échantillon complet peut être téléchargé ici
la source
let nib = loadNib(nibName)
il s'agit d'une instance XibbedView, si vous appelez `` addSubview (nib) '', alors vous ajoutez une instance XibbedView à une autre instance XibbedView?J'ai trouvé cet article de blog d'Aaron Hillegass (auteur, instructeur, Cocoa ninja) très instructif. Même si vous n'adoptez pas son approche modifiée du chargement des fichiers NIB via un initialiseur désigné, vous aurez probablement au moins une meilleure compréhension du processus en cours. J'ai utilisé cette méthode récemment avec beaucoup de succès!
la source
La réponse précédente ne prend pas en compte une modification de la structure NIB (XIB) survenue entre 2.0 et 2.1 du SDK iPhone. Le contenu utilisateur commence maintenant à l'index 0 au lieu de 1.
Vous pouvez utiliser la macro 2.1 qui est valable pour toutes les versions 2.1 et supérieures (c'est deux soulignements avant IPHONE:
Nous utilisons une technique similaire à celle-ci pour la plupart de nos applications.
Barney
la source
J'avais des raisons de faire la même chose (charger par programme une vue à partir d'un fichier XIB), mais je devais le faire entièrement à partir du contexte d'une sous-classe d'une sous-classe de
UIView
(c'est-à-dire sans impliquer le contrôleur de vue de quelque manière que ce soit). Pour ce faire, j'ai créé cette méthode utilitaire:Ensuite, je l'appelle à partir de la
initWithFrame
méthode de ma sous-classe comme suit:Publié pour l'intérêt général; si quelqu'un voit des problèmes sans le faire de cette façon, faites-le moi savoir.
la source
Voici un moyen de le faire dans Swift (en train d'écrire Swift 2.0 dans XCode 7 beta 5).
À partir de votre
UIView
sous-classe que vous définissez comme "Classe personnalisée" dans le générateur d'interface, créez une méthode comme celle-ci (ma sous-classe s'appelle RecordingFooterView):Ensuite, vous pouvez simplement l'appeler comme ceci:
let recordingFooterView = RecordingFooterView.loadFromNib()
la source
Aucune des réponses n'explique comment créer le XIB autonome qui est à l'origine de cette question. Il n'y a pas d'
Xcode 4
option pour "Créer un nouveau fichier XIB".Pour faire ça
Cela peut sembler simple, mais cela peut vous faire économiser quelques minutes, car le mot "XIB" n'apparaît nulle part.
la source
@AVeryDev
6) Pour attacher la vue chargée à la vue de votre contrôleur de vue:
Vraisemblablement, il est nécessaire de le retirer de la vue pour éviter les fuites de mémoire.
Pour clarifier: le contrôleur de vue a plusieurs IBOutlets, dont certains sont connectés aux éléments du fichier nib d'origine (comme d'habitude), et certains sont connectés aux éléments de la nib chargée. Les deux plumes ont la même classe de propriétaire. La vue chargée recouvre la vue d'origine.
Astuce: définissez l'opacité de la vue principale dans la plume chargée à zéro, cela n'obscurcira pas les éléments de la plume d'origine.
la source
Après avoir passé plusieurs heures, j'ai forgé la solution suivante. Suivez ces étapes pour créer une personnalisation
UIView
.1) Créez la classe myCustomView héritée de UIView .
2) Créez .xib avec le nom myCustomView .
3) Modifiez la classe d' UIView dans votre fichier .xib, affectez- y la classe myCustomView .
4) Créer des IBOutlets
5) Chargez .xib dans myCustomView * customView . Utilisez l'exemple de code suivant.
la source
Version la plus courte:
la source
J'ai une convention de nommer xibs avec des vues identiques à celles de la vue. Même chose que pour un contrôleur de vue. Ensuite, je n'ai pas à écrire les noms de classe dans le code. Je charge une UIView à partir d'un fichier nib du même nom.
Exemple pour une classe appelée MyView.
Dans votre code, créez un nouveau MyView comme ceci:
MyView * myView = [MyView nib_viewFromNibWithOwner: propriétaire];
Voici la catégorie pour cela:
Je câblerais ensuite les boutons avec les actions du contrôleur que j'utilise et je définirais les choses sur les étiquettes à l'aide des prises de ma sous-classe de vue personnalisée.
la source
Pour charger par programme une vue à partir d'un nib / xib dans Swift 4:
la source
J'ai fini par ajouter une catégorie à UIView pour cela:
explication ici: viewcontroller est moins de chargement de vue dans ios et mac
la source