[Résolu] PopOver incomplet au premier click
busterTheo
Membre
Bonjour,
lorsque j'affiche un popOver, le contenu ne s'affiche pas au premier click sur le barbuttonitem, mais au second.
J'ai essayé d'inverser les addSubviews dans tous les sens et c'est toujours pareil. Une idée ?
Voici la fonction complète :
func prefsPatients(sender: UIBarButtonItem) {
menuViewController.modalPresentationStyle = .Popover
menuViewController.preferredContentSize = CGSizeMake(280, 390)
let popoverMenuViewController = UIPopoverController(contentViewController: menuViewController)
popoverMenuViewController.presentPopoverFromBarButtonItem(sender, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
preferencesView = UIView(frame: CGRectMake(0, 0, menuViewController.view.bounds.size.width, menuViewController.view.bounds.size.height))
preferencesView.backgroundColor = FondsColor
preferencesView.layer.cornerRadius = 5.0
preferencesView.layer.shadowColor = UIColor.blackColor().CGColor
preferencesView.layer.shadowOffset = CGSize(width: 1, height: 1)
preferencesView.layer.shadowOpacity = 0.5
preferencesView.layer.shadowRadius = 5
menuViewController.view.addSubview(preferencesView)
let fondTitrePrefsColor = UIColor(red: 236/255, green: 236/255, blue: 236/255, alpha: 1.0)
fondTitrePrefs = UIView(frame: CGRectMake(0, 0, preferencesView.bounds.size.width, 45))
fondTitrePrefs.backgroundColor = fondTitrePrefsColor
fondTitrePrefs.layer.cornerRadius = 5.0
preferencesView.addSubview(fondTitrePrefs)
let filetTitrePrefsColor = UIColor(red: 218/255, green: 218/255, blue: 218/255, alpha: 1.0)
filetTitrePrefs = UIView(frame: CGRectMake(0, fondTitrePrefs.bounds.size.height - 2, preferencesView.bounds.size.width, 1))
filetTitrePrefs.backgroundColor = filetTitrePrefsColor
preferencesView.addSubview(filetTitrePrefs)
let labelTitrePrefsColor = UIColor(red: 124/255, green: 131/255, blue: 137/255, alpha: 1.0)
labelTitrePrefs = UILabel(frame: CGRectMake(0, 0, fondTitrePrefs.bounds.size.width, fondTitrePrefs.bounds.size.height))
labelTitrePrefs.backgroundColor = UIColor.clearColor()
labelTitrePrefs.text = "PREFERENCES"
labelTitrePrefs.font = UIFont(name: "Lato-Lig", size: 16.0)
labelTitrePrefs.textColor = labelTitrePrefsColor
labelTitrePrefs.textAlignment = .Center
fondTitrePrefs.addSubview(labelTitrePrefs)
let labelEnableAideColor = UIColor(red: 80/255, green: 80/255, blue: 80/255, alpha: 1.0)
labelEnableAide = UILabel(frame: CGRectMake(10, fondTitrePrefs.bounds.size.height + 10, 190, 20))
labelEnableAide.backgroundColor = UIColor.yellowColor()
labelEnableAide.text = "Aide automatique"
labelEnableAide.font = UIFont(name: "Arial", size: 14.0)
labelEnableAide.textColor = labelEnableAideColor
labelEnableAide.textAlignment = .Left
preferencesView.addSubview(labelEnableAide)
let SwitchEnableAideColor = UIColor(red: 135/255, green: 261/255, blue: 107/255, alpha: 1.0)
switchEnableAide = UISwitch(frame: CGRectMake(preferencesView.bounds.size.width - 70, fondTitrePrefs.bounds.size.height + 3, 30, 20))
switchEnableAide.tintColor = SwitchEnableAideColor
switchEnableAide.setOn(false, animated: true)
switchEnableAide.addTarget(self, action: "masqueAutoAide:", forControlEvents: .ValueChanged)
preferencesView.addSubview(switchEnableAide)
let fetchRequest = NSFetchRequest(entityName: "Preferences")
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [Preferences] {
if fetchResults.count != 0 {
if fetchResults[0].aide == true {
switchEnableAide.setOn(true, animated: true)
} else {
switchEnableAide.setOn(false, animated: true)
}
} else {
switchEnableAide.setOn(true, animated: true)
let newPref = NSEntityDescription.insertNewObjectForEntityForName("Preferences", inManagedObjectContext: self.managedObjectContext!) as! Preferences
newPref.aide = true
var appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var context: NSManagedObjectContext = appDel.managedObjectContext!
let entity = NSEntityDescription.entityForName("Preferences", inManagedObjectContext: context)
context.save(nil)
}
}
}
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Et en plus, on remarque que j'ai un dismiss qui fonctionne, alors que je n'ai implémenter aucune méthode dismiss - Oups !!!
Genre du coup ta vue principale est créée plus large que prévu par ton code, tu places tes éléments en espérant qu'elle va rester à cette largeur, mais en fait quand elle est affichée elle est moins large, et du coup le Swift que tu avais mis à 90px de la droite de ta vue, bah en fait il est un peu trop à droite maintenant que la vue est moins large...
Tu dois pouvoir le voir en passant Xcode en mode "vue explosée" lors du debug pour débuguer ton UI et mieux voir où se cache le switch (c'est justement un outil idéal pour ce genre de problème, autant s'en servir)
Mais bon, c'est ça aussi de faire de l'UI en mettant des magic numbers partout, et surtout en n'utilisant pas AutoLayout(ni les AutoResizingMasks appropriés si tu voulais le faire à l'ancienne), ce qui fait que quand ta vue est redimensionne forcément le reste ne suit pas... c'est pas étonnant du coup.
Et puis ceci dit, quelle drôle d'idée de faire ses interfaces tout en code en dur comme ça (ce qui non seulement est difficilement lisible et très peu visuel, mais en plus ne te montre pas les warnings de contraintes manquantes ni les impacts que peut avoir le redimensionnement sur ta vue...), au lieu de les faire dans un XIB...
Je ne pratique pas le swift. En objective-c, les nombre comme 124/255 seront égaux à 0 (division entre deux entiers). En Swift, ce n'est plus le cas ?
Ben honnêtement, j'utilise cette façon de faire depuis le début, car c'est ce que j'ai vu partout, mais je n'en sais pas plus.
En tout cas, ça a l'air de bien fonctionner, mais je ne suis pas un expert...
Mon projet sera exclusivement pour iPad2 en position paysage. Donc pas de redimensionnement, ni rotation, je n'ai donc à priori pas à me prendre la tête avec ces histoires de autoLayout, etc. Qu'en penses-tu ? Je fais fausse route ?
J'ai résolu le problème en créant une constante :
et ça fonctionne nikel. Merci pour ton explication sur la vue principale.
Alors là , j'ai cherché partout, et je n'ai rien trouvé sur la vue explosée (exploded view). Je crois que je ne sais pas utiliser le mode debug. J'y comprend rien. Pour débuguer, tracer mes variables, etc, je fais ça à l'ancienne, avec des println...
J'ai vu ta remarque là -dessus. Et puis le lien wikipedia. Merci pour ça.
Donc, si j'ai bien compris, on ne doit pas faire ça :
mais créer des constantes (comme mon truc plus haut). Mais dois-je le faire pour tous les nombres, car y'en a partout des trucs comme ça. En tout cas, dans la majeure partie, surtout si je les ré-utilise, j'ai créé des constantes, mais pour les autres... Bof.
Ouais, c'est vrai que c'est pas mal le coup des xibs. Est-ce vraiment mal de faire tout en code ?
Est-ce que ça consomme plus de mémoire, ou ça fait d'avantage bosser le proce ?
Qu'est-ce qui est vraiment le mieux ?
Indépendamment de la lisibilité, car j'essaie au maximum de faire un code propre, bien séparé, et commenté. Bon, il est certain que je peux encore faire mieux dans ce dommaine. Et puis, je suis codeur depuis toujours, j'ai donc un peu de mal avec les interfaces graphiques. Et en plus, mais ça c'est mon côté idiot, du fait que je ne suis pas ingénieur, cela fait du bien à mon ego.
En tout cas, merci AliGator pour tes efforts. Je vais m'empresser d'aller lire ton pur cours sur ce lien.
Oui. Car qu'est-ce qui va empêcher l'utilisateur de ton application de la lancer sur un iPad Mini par exemple ? Et quid des modes SlideOver et SplitView par exemple sur iOS9 ? Ou si Apple sort une nouvelle dimension d'iPad en octobre ?
Alors après c'est sûr que tu peux te dire que tu vas prendre des raccourcis et moins te prendre la tête car tu n'auras pas 36 dimensions à gérer, surtout si par exemple en fait ton application est faite pour être installée dans des bornes sur iPad 2 et pas distribuée via l'AppStore où elle pourrait être installée sur n'importe quel iPad... mais ça n'empêche pas, à défaut d'utiliser AutoLayout, d'au minimum utiliser les AutoresizingMasks pour correctement fixer la position de ton UISwitch en fonction de la droite de ta vue et non pas de sa gauche comme c'est le cas avec l'ARMask par défaut.
C'est pourtant documenté ici et Ray Wenderlich a également un tuto dessus.
Il serait peut-être grand temps de t'y intéresser, car cela va te gagner un temps fou pour débuguer tes problèmes de code. Ce n'est pas bien compliqué et pourtant super puissant, rien que de mettre un Breakpoint (ce qui se fait en un clic) t permet ensuite de faire du pas à pas instruction par instruction, et de regarder les valeurs des variables en live sans avoir à rajouter un println() dans le code, puis recompiler ton code et relancer ton app depuis le début pour retomber sur le même endroit dans le code...
Ce n'est pas bien sorcier et tu vas gagner énormément en productivité, donc c'est un tort de ne pas s'y pencher pour mieux comprendre comment ça marche.
Pas forcément pour TOUS les nombres, mais pour toutes les valeurs qui semblent sortir de nulle part ça reste quand même non seulement pratique, plus lisible, mais aussi et surtout ça permet d'éviter des problèmesplus tard, surtout si certaines valeurs sont dépendantes d'autres valeurs.
- Par exemple mettre en dur la largeur ou hauteur de l'écran est une très mauvaise idée, car si demain ton app doit tourner sur une autre résolution d'écran (ou que ton utilisateur branche un écran externe à l'iPad, etc) ça ne marchera plus, alors que ces valeurs de largeur et hauteur de l'écran tu peux les récupérer. En vrai tu ne veux pas que ta vue fasse par exemple 1024 de large, mais plutôt qu'elle fasse la largeur de tout l'écran, donc c'est plutôt ça qu'il faut exprimer plutôt que de mettre une valeur de 1024 comme ça en dur.
- Utiliser des constantes permet de les réutiliser, même si de prime abord tu as l'impression qu'elle ne sera pas utilisé autre part pour l'instant. Par exemple des constantes pour les dimensions de ta popover vont être utiles à la fois pour calculer les dimensions de tes autres éléments (labels, etc) en conséquence pour les placer au bon endroit en fonction de la largeur et hauteur de ta popover (tu veux pas le label à "x=190" mais plutôt à "x = largeurPopover-marges-largeurSwitch" même si aujourd'hui le résultat de ce calcul vaut effectivement 190), mais aussi soit pour affecter la popoverContentSize, soit pour modifier la taille de ton menuViewController que ton UIPopoverController présente, pour que toutes les tailles utilisées soient consistantes
- Si tu as des valeurs qui dépendent les unes des autres, il faut mieux utiliser des constantes et écrire les calculs entre les constantes plutôt que d'écrire la valeur du résultat en dur. Par exemple plutôt que d'indiquer que la largeur de ton label est de 190px, ce que tu veux en vrai c'est plutôt indiquer que ton label prend toute la largeur de ta popop, moins quelques marges à gauche et à droite, moins la largeur de ton UISwift que tu mets à sa droite. Comme ça si demain tu changes la constante indiquant la largeur de ta popover parce que tu as décidé que tu la voulais finalement plus ou moins large, tout va suivre tout seul en ne changeant que la constante popoverWidth que tu auras créé, puisque tous les autres éléments seront calculés en fonction d'elle.
Et j'en passe, les avantages et conséquences sont nombreuses, surtout pour quand tu reprendras ton code dans plusieurs mois et voudra changer juste une valeur qui va être dure à retrouver et dont le changement va tout casser si tu n'as mis que des valeurs en dur partout plutôt que des constantes et des calculs selon ces constantes.- Réduire drastiquement ton nombre de lignes de code (par exemple tout ce que tu as écrit ici ne tiendrait qu'en une seule ligne, qui va charger le XIB)
- Augmenter la maintenabilité du code, car perso moi quand je vois tout le code que tu as mis juste pour créer ton interface je ne vois pas du tout à quoi va ressembler l'UI rien qu'en lisant le code comme ça d'une traite. Tout le monde n'est pas capable de lire dans la matrice aussi facilement pour voir à quoi va ressembler ton UI en fonction du code de création des UIViews que tu as mis, donc ça n'aide pas pour la maintenance, que ce soit si qqn d'autre reprend ton code ou si toi tu dois le reprendre dans 8 mois.
- Etre plus visuel lors de l'édition de ton interface, il suffit par exemple d'un simple drag & drop pour placer un bouton à l'endroit voulu.
- Cette facilité d'édition comprend aussi l'usage des guides, pour aligner par exemples les centres ou bords d'un élément avec les autres facilement, etc
- Sans parler évidemment de la facilité de placer les AutoresizingMasks (ou les contraintes AutoLayout) dans IB, par opposition à le faire via le code. De plus en faisant ainsi, si tu redimensionnes ta vue parente dans IB, tout le contenu va suivre correctement (touche Cmd)et s'étirer comme il faut, sans que tu aies besoin de modifier tes frames partout dans le code si tu faisais sans IB
- Prévisualiser immédiatement le rendu de tes écrans dans diverses configurations (Portrait, Paysage, iPhone 3.5", iPhone 4", iPhone 6Plus, iPad, ...) grâce au mode "Preview" de l'Assistant IB
- Pouvoir faire des mesures directement sur l'interface (avec la touche alt + survol des éléments) pour vérifier que tes placements sont conformes à ce que toi ou ton graphiste avez prévu
- Connecter les delegates ou autres IBOutlets & les IBActions très facilement par drag & drop
- Rendre ta vue réutilisable très facilement. Tu peux même pré-charger l'arborescence des vues décrites par ton XIB dans un UINib puis l'instancier ensuite autant de fois que tu veux sans qu'il n'ait à re-parser toute l'arborescence. C'est sur ce genre d'astuces que se base UITableView pour faire le recyclage des cellules et augmenter les performances lors du scroll en évitant ainsi de faire laguer ton interface
- Et enfin, rien n'empêche de mixer XIB et code, c'est même parfois utile voire indispensable. Tu fais alors la majorité de ton code en XIB, ce qui te permet d'avoir un rendu visuel, une preview immédiate du rendu dans tous les contextes possibles via l'assistant, et de composer ton UI en quelques secondes au lieu d'avoir à écrire plein de code pour ça... et si tu as des trucs que tu ne peux pas faire via IB, ou que tu veux ajuster par code, rien n'empêche d'avoir des IBOutlets vers tes éléments de ton XIB et de modifier leurs propriétés ou ajuster quelques réglages sur ces vues par code, mais ça reste quand même beaucoup plus lisible et maintenable et moins verbeux que de tout faire en code
Après, ce n'est pas "un mal absolu" que de tout faire en code, c'est pas genre une erreur grossière de codage (comme le serait l'utilisation des unwrapped optionals à tout bout de champ par exemple), c'est juste un choix, mais c'est quand même un choix qui fait que tu perds pas mal d'avantages offerts par IB. C'est un peu comme si tu tapais ton code dans TextEdit ou TextWrangler : tu as le droit, rien ne t'en empêche, mais tu n'aurais alors pas tout ce que t'offre Xcode comme l'autocomplétion, l'auto-indentation, la coloration syntaxique... bah faire toute ton UI exclusivement en code, ça me donne un peu cette même impression, tu as le droit mais tu perds beaucoup d'avantages.Donc tu suggères que je remplacemes 124/255 par 124/255.0 ou par 124.0/255.0 ? J'ai compris par 124/255.0...
Ben pour l'instant, la commande était ipad2 paysage. Pur le reste on verra une V2 ou V3, vu la deadline serré, je vais plutôt me consacrer au reste de ma construction. Il sera mis en ligne sur appStore avec cette compatibilté : ipad2 paysage, uniquement.
Je ne connaissais pas. Merci. C'est du sérieux tout ça. Je suis allé voir également ceci que j'avais déjà observé, et ceci https://developer.apple.com/videos/wwdc/2014/#413 qui semble d'avantage me concerner.
J'ai fait tous les exos sur touts ces sujets. J'avour que les manips du debugger sont excellente.
Mais moi, ce qui me m'intéresse pour l'instant, c'est surtout pister mes variables (valeurs, nil, optionnal, ! et ?, avec le debugger plutôt qu'avec mes println, et là je n'ai pas tout compris, ça semble un peu complexe et laborieux pour moi. Impossible de suivre mes variables mieux que avec des printlns. Mais je vais persister à mes moments perdus. Je ne lacherai pas l'affaire. Promis.
Sur mon IB, j'ai cocher depuis le début les cases "Use autoLayouts" et "UseSizeClass", sur tous mes controllers qui se remplissent presque tous par le code.
J'avoue que je ne sais pas du tout régler ces trucs par le code. J'ai essayé des tas de trucs touvés sur le web, et il ne passe rien, (surtout car je n'y comprend rien. Sur quelle view caler ce truc ?). Et est-ce nécessaire, à partir que je l'ai défini dans l'IB ?
À ce propos, je n'utilise jamais "frame: CGRectMake(0, 0, 1024, 768)" sauf pour une image d'intro ("imageViewIntro = UIImageView(frame: CGRectMake(0, 0, 1024, 768))").
Aurais-je des roblèmes sur les écrans de résolutions "2048x1536" en "264dpi" et sur les écrans "2048x1536" en "326dpi".
Toutes mes images sont conçues en "264dpi" à partir de psds de "1024x768".
Et sur les prise de vues avec le camera, je vois que les images feront 1,2Mpx et la résolution des vidéos de HD 720p.
Dans quelle mesure dois-je tenir compte de tous ces paramètres, à savoir que j'avais cru comprendre que depuis les retina, on n'avais pas à s'occuper de cela, dixit la notion de profondeur des pixels, qui gérait la correspondance entre 1024 et 2048. Tout ça est un peu confus pour moi. J'ai ce lien apple.
Pour les magicNumbers, ok j'ai compris.
Ainsi que pour les xibs/code.
Je développe le projet pour iOS8.4. ça ira ? - Pas de fonctionnalité iOs9 - Et il n'y en aura pas avant un V2 ou une V3, et ce sera refacturé, car la commande est précise : iPad2 paysage iOs8 et pas d'autre pour l'instant, surout vu les délais hyper courts.
Merci pour tes explications...
Il n'est pas possible de spécifier le modèle de iPad que tu veuilles cibler, seulement la version de iOS. un iPad 2 peut soutenir de iOS 4.3 jusqu'à iOS 8.4 et, si je ne me trompe pas, iOS 9.
Du coup, n'importe quel modèle d'iPad, tant que tu as ciblé une version entre le minimum pour le modèle, ça ira.
Ah cool tout ça, merci Joanna Carter, et pour les histoires de résolutions/définition/profondeurs, c'est la même, c'est réglé en auto par Apple ? À partir du moment où j'évite d'utiliser des tailles précises dans mon code (genre 1024x768) - Y'aura pas de pb sur les 2048x1536 qui seront gérée par la profondeur (retina) ?
Et donc mes images de fond 1024x768 ainsi que les images chargées par les utilisateurs (camera, albums, dropbox) pas de pb non plus, quant aux tailles résolutions/etc. ?
J'ai de sérieux doutes sur tout ça, depuis le début de mon projet. J'angoisse grave à ce sujet...
Y'a des risques que tu te fasses refuser la publication si ton application ne marche pas sur certains iPads mais que sur un seul modèle. Maintenant il se trouve que tous les iPads ont la même résolution (en nombre de points) donc si c'est que ça, ça va... mais bon, c'est quand même pas très flexible (si en Octobre Apple sort un iPad d'une résolution différente, t'es foutu...)
Et ça c'est sans parler du support de SplitView et SlideOver qui vont apparaà®tre comme possibilité pour ceux qui auront des iPad Air 2 sous iOS9. Certes tu n'y es sans doute pas encore mais ça impacte quand même tes futurs utilisateurs (et si tu mets des valeurs en dur type Magic Numbers au lieu d'utiliser des constantes ou de demander les tailles au runtime, la migration va être d'autant plus chronophage que si tu prévoyais dès maintenant le nécessaire. Perdre 1h aujourd'hui t'évitera d'en perdre 5 demain.
Tout à fait !
Pourtant, ça fait partie de ce qu'il y a de plus simple parmi les opérations à faire avec le débugguer. Tu places un breakpoint, et quand ton exécution s'arrête sur ce breakpoint, bah... t'as rien à faire, t'as juste à regarder dans l'inspecteur de variables en bas de l'écran Xcode où il t'affiche toutes les variables locales qui sont dans le scope et leurs valeurs. Y'a pas vraiment plus simple !
Tout ce que tu fais dans IB est la même chose que si tu faisais l'équivalent dans le code. Donc non, il n'y a aucun intérêt à le refaire par le code si tu l'as déjà réglé dans IB (ça n'aurait aucun intérêt sinon !)
Et par contre, c'est bien beau de cocher "Use AutoLayouts" dans ton document IB, mais si en pratique tu ne places pas de contraintes, ça sert à rien. C'est comme ajouter une serrure à une porte mais en pratique ne jamais la fermer à clé.
- Si tu as choisi de cocher "Use AutoLayouts" pour activer la fonctionnalité, encore faut-il ensuite rajouter toi-même des contraintes.
- Si tu trouves AutoLayout compliqué pour ton usage (ce que je peux comprendre si tu ne t'y es pas encore mis), tu peux tout à fait désactiver "Use AutoLayouts" pour désactiver la fonctionnalité et utiliser les AutoResizingMasks à la place. Mais là encore, c'est bien beau de dire à ton XIB que tu utiliseras AutoResizingMask au lieu d'AutoLayout, mais encore faut-il correctement ensuite configurer les masques d'AutoResizing sur chacune de tes vues, sinon ça n'a aucun intérêt.
L'AutoResizingMask par défaut étant de caler la vue en haut à gauche et ne pas changer sa taille, ça ne convient évidemment pas pour ton UISwitch, pour lequel c'est la position du côté droit qu'il faut conserver, et non pas la distance au côté gauche, mais si tu n'as pas configuré ça ni dans ton XIB ni par code, ça risque pas de deviner ça tout seul comme par magie.
Non, pas de soucis directement car les dimensions (type frames) sont exprimées en points, et non pas en pixels, et les écrans de tous les iPads qui sont pour l'instant sur le marché font tous 1024x768 points.
Mais là encore, si demain tu as un nouvel iPad qui sort avec une dimension en points différente, ça va tout casser.
Quel est l'intégrer de mettre en dur une telle frame avec des valeurs tapées à la main, alors que UIApplication.sharedApplication.window.frame te fournit déjà cette valeur directement, et en plus s'adapte tout seul si un jour ton code tourne sur un device ayant une résolution en points différente de 1024x768. C'est pas comme si t'avais à écrire plein de ligne de code en plus, c'est juste "UIApplication.sharedApplication.window.frame" au lieu de mettre ton CGRect en dur, donc t'as pas trop d'excuse ^^
Bon, ok AliGator.
J'ai bien noté tous tes conseils.
Encore grand merci pour tes efforts, à moi d'aviser et d'assurer.
C'est un peu la panique, il faut que j'intègre tout cela.