J'ai du mal à supprimer toutes les sous-couches de la couche. Je fais actuellement cela manuellement, mais cela apporte un encombrement inutile. J'ai trouvé de nombreux sujets à ce sujet dans Google, mais aucune réponse.
J'ai essayé de faire quelque chose comme ça:
pour (CALayer * couche dans rootLayer.sublayers) { [couche removeFromSublayer]; }
mais ça n'a pas marché.
En outre, j'ai essayé de cloner rootLayer.sublayers dans NSArray séparé, mais le résultat était le même.
Des idées?
Modifier:
Je pensais que cela fonctionne maintenant, mais je me trompais. Cela fonctionne bien avec CALayers, mais cela ne fonctionne pas avec CATextLayers. Des idées?
La façon la plus simple de supprimer toutes les sous-couches d'un calque consiste à définir la propriété de la sous-couche sur zéro:
rootLayer.sublayers = nil;
Les éléments suivants devraient fonctionner:
for (CALayer *layer in [[rootLayer.sublayers copy] autorelease]) {
[layer removeFromSuperlayer];
}
[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
Swift (version courte):
layer.sublayers?.forEach { $0.removeFromSuperlayer() }
L'appel de rootLayer.sublayers = nil;
Peut provoquer un plantage (par exemple, si sous iOS 8, vous appelez removeFromSuperview deux fois sur la vue possédant rootLayer
).
La bonne façon devrait être:
[[rootLayer.sublayers copy] makeObjectsPerformSelector:@selector(removeFromSuperlayer)]
L'appel à copy
est nécessaire pour que le tableau sur lequel removeFromSuperlayer
est appelé itérativement ne soit pas modifié, sinon une exception est levée.
Les deux paramètres self.view.layer.sublayers = nil
et [layer removeFromSuperlayer]
entraînera un plantage si UIView
contient une sous-vue. La meilleure façon de supprimer CALayer
de superLayer est de conserver un tableau de couches. Par exemple, ce tableau est arrayOfLayers,
Chaque fois que vous ajoutez un calque sur UIView.sublayer
ajoutez cette couche dans ce tableau ...
Par exemple
[arrayOfLayers addObject:layer];
[self.view.layer addSublayer:layer];
Tout en supprimant, appelez simplement cela,
[arrayOfLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
La suppression aveugle de toutes les sous-couches provoque des plantages désagréables dans iOS 7, qui peuvent survenir beaucoup plus tard dans l'exécution du programme. J'ai testé cela en profondeur en utilisant à la fois rootLayer.sublayers = nil
Et [rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]
. Il doit y avoir une couche créée par le système qui se gâche.
Vous devez conserver votre propre tableau de couches et les supprimer vous-même:
[myArrayOfLayersIAddedMyself makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
Que diriez-vous d'utiliser l'énumération inverse?
NSEnumerator *enumerator = [rootLayer.sublayers reverseObjectEnumerator];
for(CALayer *layer in enumerator) {
[layer removeFromSuperlayer];
}
Parce que le groupe en sous-couches est modifié lors du dénombrement, si l'ordre est normal. Je voudrais connaître le résultat du code ci-dessus.
J'ai essayé de supprimer uniquement la première sous-couche à l'index 0 et cela a fonctionné:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cell.contentView.layer.sublayers count] != 0) {
[[cell.contentView.layer.sublayers objectAtIndex:0] removeFromSuperlayer];
}
J'ai rencontré le même problème et trouvé de nombreuses solutions, mais aucune n'est parfaite.
Enfin de réponse ci-dessus de pnavk j'ai eu l'idée. Là, le code est destiné aux utilisateurs de Xamarin/C #.
La version iOS pourrait être la suivante:
Swift 2.3
if rootLayer.sublayers?.count > 0 {
rootLayer.sublayers?.forEach {
if $0.name == "bottomBorderLayer" {
$0.removeFromSuperlayer()
}
}
}
let border = CALayer()
let height = CGFloat(1.0)
border.borderColor = UIColor.blackColor().CGColor
border.borderWidth = height
border.frame = CGRectMake(0, self.frame.size.height - height, self.frame.size.width, self.frame.size.height)
border.name = "bottomBorderLayer"
rootLayer.addSublayer(border)
rootLayer.masksToBounds = true
Objectif-C
if (rootLayer.sublayers.count > 0) {
for (CALayer *layer in rootLayer.sublayers) {
if ([layer.name isEqualToString:@"bottomBorderLayer"]) {
[layer removeFromSuperlayer];
}
}
}
CALayer *border = [[CALayer alloc] init];
CGFloat height = 1.0;
border.borderColor = [UIColor blackColor].CGColor;
border.borderWidth = height;
border.frame = CGRectMake(0, self.view.frame.size.height - height, self.view.frame.size.width, self.view.frame.size.height);
border.name = @"bottomBorderLayer";
[rootLayer addSublayer:border];
rootLayer.masksToBounds = TRUE;
Le code ci-dessus ne fonctionnera que pour la bordure inférieure. Vous pouvez changer le côté de la bordure selon vos besoins.
Ici avant d'ajouter une couche au contrôleur, je viens de lancer une boucle for pour vérifier si une bordure est déjà appliquée ou non?
Pour identifier la bordure ajoutée précédemment, j'utilise la propriété name de CALayer. Et comparez cette couche avant de la supprimer des sous-couches.
J'ai essayé le même code avant d'utiliser la propriété name, mais cela crée un plantage aléatoire. Mais après avoir utilisé la propriété name et comparé le nom avant la suppression, le problème de plantage sera résolu.
J'espère que cela aidera quelqu'un.
J'ai dû le faire dans Xamarin/C #. J'avais un UITableViewCell
avec un CAShapeLayers
pour les bordures. Toutes les options ci-dessus (y compris la copie du tableau puis la suppression des calques ont provoqué un plantage). L'approche qui a fonctionné pour moi:
Lors de l'ajout de CALayer
, je lui ai donné un nom:
var border = new CALayer();
border.BackgroundColor = color.CGColor;
border.Frame = new CGRect(x, y, width, height);
border.Name = "borderLayerName";
Layer.AddSublayer(border);
Dans PrepareForReuse
sur le UITableViewCell
, j'ai créé une copie de la propriété SubLayers
et supprimé tout ce qui correspondait au nom que j'ai attribué précédemment:
CALayer[] copy = new CALayer[Layer.Sublayers.Length];
Layer.Sublayers.CopyTo(copy, 0);
copy.FirstOrDefault(l => l.Name == "borderLayerName")?.RemoveFromSuperLayer();
Aucun plantage.
J'espère que cela t'aides!