[Résolu] une custom cell avec iboutlets et drawRect ?
Salut,
j'aimerais mettre un fond dans une custom cell, et utiliser les iboutlets pour changer le texte etc. Mais:
EDIT: je voudrais utiliser CoreGraphics pour customizer ma cell, or les méthodes draw... n'affichent pas le code. En suivant les conseils, j'essaie de faire une sous-classe de layer, et de l'ajouter dans ma custom cell, avec une méthode drawInContext... mais le code ne s'affiche pas. La cell est blanche, le texte est bien updaté, mais rien niveau CoreGraphics...
il vaut mieux passer directement à ce post plus bas, avec le code : lien
_______________
Code:
@synthesize ibLabel;
-(void) addBackground{
UIView *view = [[UIView alloc] initWithFrame:self.frame];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor blackColor] CGColor], nil];
[view.layer insertSublayer:gradient atIndex:0];
[self addSubview:view];
//[self.layer addSublayer:view.layer];//pariel que addSubview
}
- (void)awakeFromNib {
//self.backgroundColor = [UIColor clearColor]; //ne marche pas
//[self addBackground];
self.ibLabel.text = @hello;//ne s'affiche pas quand je met addBackgorund
}
- je peux utiliser drawRect dans une custom class si cette custom class est initialisée comme la "backgroundview" de la cell, la cell entière est une UITableViewCell et sa backgroundView est ma custom class, mais dans ce cas, je n'ai plus accès aux iboutlets:
Code :
- (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@Cell forIndexPath:indexPath];
//mais dans ce cas, la custom cell change uniquement le fond de ma cell, je n'ai pas accès aux IBOutlets
if (![cell.backgroundView isKindOfClass:[MyCell class]]) {
cell.backgroundView = [[MyCell alloc] init];
}
return cell;
}
> faut-il que je crée une class pour le .xib avec les labels et iboutlets, et une autre class avec drawRect uniquement pour le background? C'est pas un peu bizarre d'avoir 2 classes pour une custom cell?
Merci ;-)
Réponses
Pour la deuxième question, il faut utiliser -[UITableView registerNib/Class:forReuseIdentifier:]. Dans le xib définissant la cellule, change la classe de la cellule en ta classe, puis tire les outlets.
D'accord, merci, alors j'utilise les layers plutôt que drawRect. Mais :
EDIT: problème de taille réglé.
En plus, ne fais ni l'addition ni l'insertion des vues ou des couches dana la méthode cellForRowAtIndexPath - les cellules renvoyées par dequeueReusableCellWithIdentifier peuvent déjà avoir les vues ou couches de leurs dernière utilisation.
Il vaut mieux sous-classer une cellue et de mettre le code de création des sous-vues et couches dans la méthode awakeFromNib
EDIT: problème de taille réglé.
Alright, parfait, merci beaucoup ça marche
Voilà le code
EDIT: > comment utiliser CoreGraphics (comme le code ci-dessous) et l'afficher dans une layer, pour customiser la cell?
Joanna saurais-tu comment ajouter le code qui serait normalement dans drawRect:, à l'intérieur d'une layer que je pourrais mettre dans ma custom cell class ?
J'ai trouvé un exemple dans la doc, mais la ligne (stripe) est dessinée dans un "context", je ne sais pas bien comment je pourrais mettre ça dans une layer, et ensuite la mettre dans une subView de ma custom cell : (le lien de la doc pour faire le drapeau américain : lien)
De plus, j'ai lu dans un message sur SO, que on peut utiliser drawRect: dans une custom cell, et drawRect est bien appelé quand je met un NSLog, mais rien n'est dessiné... alors, quelle est la bonne réponse?
Merci
Bonjour Lou,
il y a une raison pour laquelle tu veux absolument un layer supplémentaire ?
Si oui, tu peux créer une sous-classe de CALayer, que tu ajoutes à l'init de la cell, et tu mets ton code dans le DrawInContext ?
Si tu utilises un xib, pourquoi tu ne sous-classes pas ta backgroundView pour y dessiner ce que tu veux ?
Salut Booleanne,
en fait je ne sais pas comment faire, je voudrais simplement pouvoir utiliser le iboutlet depuis le uiviewController, et sous-classer la cell pour pouvoir mettre le design que je veux. Il y a plein d'exemple avec Core Graphics dans la méthode draw..., mais rien ne s'affichait, donc j'ai suivi les conseils de Joanna et j'ai fait des sublayers. Or je n'arrive pas à appeler les méthodes draw... de cette subLayer.
Pour tes deux solutions :
La uiView, je ne sais pas bien comment faire, seulement le initWithFrame sort dans la console, le drawRect ou autres tests n'apparaissent pas.
Pour le layer, j'ai juste mis drawInContext mais rien ne s'affiche non plus dans la console, aurais-tu un exemple à me montrer?
Voilà le code :
Ton sublayer, je l'ajouterais non pas à ta cell, mais à ta MyBV, et le backgroundView, en IBOutlet, c'est ta MyBV.
Lou, ce que tu voulais, c'est comme l'image ci-jointe ?
>EDIT: Merci, mais je ne parviens toujours pas à afficher le rectangle rouge dans ma cell (le code de mon subLayer avec drawInContext...)
Joanna, je voudrais rajouter un rectangle rouge sur toute la largeur en bas de la cell, mais c'est surtout pour tester et savoir comment utiliser les drawRect/InContext dans mon code.
> Pour l'instant, mySubLayer, avec le drawInContext, ne m'affiche rien...
C'est pourquoi que tu veux dessiner dans une couche ?
Moi, j'ai fait un projet d'essai dans laquel je peux remplacer le gradient avec n'importe quelle vue sans aucune ligne de code
Qu'est-ce que tu veux exactement ?
> En fait, je voudrais simplement utiliser les méthodes draw... pour utiliser CoreGraphics dans une custom cell.
Par exemple, en créant une ligne rouge assez épaisse (un rectangle) mais je ne parviens pas à utiliser les méthodes draw... dans cette custom cell.
J'ai réussi à le faire uniquement quand je crée une sous-classe et que je fais : "cell.backgroundView = myCell;"
Mais j'aimerais mettre le design, et les iboutlets dans le même code, c'est-à -dire tout rénuir dans ma cell : le code customisé avec CoreGraphics pour le design, et changer le texte et autres data grâce au UIViewController. (donc avoir une sous-classe de ma custom cell dans le uiViewController, comme c'est le cas actuellement, mais je ne parviens pas à jouer sur le design)
Certains messages sur SO disent qu'on peut utiliser drawRect dans la custom cell, et Joanna tu me dis qu'il vaut mieux faire des sublayers...
-pour le drawRect:
je n'y arrive pas, drawRect ne s'affiche pas, alors j'essaie de le mettre dans une sous-classe comme suggéré plus haut
- dans une sous-classe de layer, drawInContext n'est pas appelé. Le init de cette sous-classe est bien appelé, mais pas sa fonction draw...
Donc... je suis bloqué.
Je ne souhaite pas tout faire dans le xib car je voudrais utiliser CoreGraphics.
Si je t'ai bien entendu, pour dessiner sur une cellule, il ne faut que sous-classer UIView en implémentant la méthode drawRect comme tu veux. Puis, dans le xib, tu ajoutes un UIView comme sous-vue et le mettre en place sur le contentView avec les contraintes d'autolayout, tu sélectionnes le UIView, tu choisis la palette "Identity Inspector" et tu saisis le nom de ta classe au lieu de UIView. Il n'est pas nécessaire de toucher les couches.
Comme te l'explique Johanna très bien, en sous-classant ta view, tu pourras utiliser CoreGraphic, dans le drawRect. Dans tous les cas tu n'as pas vraiment le choix, c'est de cette façon que tu peux dessiner tes vues librement.
Les sublayers, on les utilise quand on a besoin de différents calques pour une vue.
Merci,
alors le résultat :
avec UIVIew, aucun problème finalement, une subView dans la custom cell, et le drawRect, marchent très bien.
Pour tester, j'ai voulu faire la même chose, avec un layer, et j'ai trouvé ce site qui résume (lien) la démarche :
1/ soit on init un CALayer, on set le delegate (dans self, ou dans myBV), et on setNeedsDisplay, et on utilise drawLayer:inContext:
2/ soit on crée une sous-classe de CALayer, et on utilise drawInContext:
Pour le 1/ et 2/ : j'ai un exc_bad_access
Pour le 1/ : c'est dans la custom cell : quand j'ajoute le layer ou la custom view à l'intérieur du contentView
Pour le 2/, c'est dans le uiviewController, à la ligne "dequeueReusableCellWithIdentifier"
Le code :
Et je ne sais pas comment trouver le bug suite à un exc_bad_access.
Voilà Si vous avez une idée, alors je serais intéressé de savoir ce qui se cache derrière ce bug.
Sinon, j'utiliserai uniquement les uiview sans trop comprendre le problème
Je ne suis pas sure, mais ton erreur vient peut-être du fait que tu demandes au CALayer de se redessiner, alors qu'il n'est pas affiché.
Il faut plutôt mettre ton setNeedsDisplay à l'appel de la Cell (dans le CellForRowAtIndexPath).
De ce que j'entends de l'article, je crois que, si tu utilises les layers pour un tel simple scénario, c'est un cas d'optimisation précoce ; contentes-toi d'utiliser la subView
Je pencherai pour la même explication que booléanne.
J'ai testé comme ça :
Mais il y a toujours l'erreur exc_bad_access...
As-tu un projet test que tu pourrais nous envoyer pour que l'on teste ?
Je crois que tu ne t'y prends pas comme il faut. Je confirme déjà ce que te dis Johanna : inutile de t'embêter avec un CALayer. Mais comme j'ai l'impression que tu y tiens vraiment, dans un premier temps, supprime ce que tu as mis dans awakeFromNib.
Tu peux aussi supprimer ton drawlayer, il est appelé dans ton CALayer, pas dans ta cell.
Ensuite, si tu as toujours ta classe bgView, ajoute-lui un CALayer en variable. A l'init de ton bgView, alloue ton CALayer et ajoute-le à ta bgView;
Après ça :
MyCell *cell = (MyCell*)[tableView dequeueReusableCellWithIdentifier:@Cell forIndexPath:indexPath];
[cell.contentView addSubview:bgView];
Normalement, si je n'ai rien oublié, ça doit fonctionner. Mais du coup, pourquoi tu ne te contentes pas du drawRect de ta view ?
Si c'est juste pour t'entraà®ner, le meilleur moyen n'est pas de l'utiliser dans une cell.
Salut Booleanne,
non je n'y tiens pas forcément C'est pour comprendre, c'est tout. D'après ce que j'ai pu lire, une layer peut être rajoutée à une view, et on peut empiler les layer dans une view. Mais les méthodes de la layer ne sont pas appelées, alors je voulais comprendre pourquoi
J'ai essayé ce que tu as dit, mais seulement les "init..." s'affichent, et le drawRect de la view. Je n'ai pas les draw... du layer avec ce code dans le MasterViewController :
Donc je vais rester avec les subview
Merci pour vos réponses
Le reste du code me paraà®t plus cohérent, maintenant. Mais à priori ton sublayer n'a pas de frame.
Super, c'est top. Merci beaucoup