web-dev-qa-db-fra.com

Suppression de toutes les sous-couches de CALayer

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?

59
radex

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;

125
Pascal Bourque

Les éléments suivants devraient fonctionner:

for (CALayer *layer in [[rootLayer.sublayers copy] autorelease]) {
    [layer removeFromSuperlayer];
}
33
Ben Gottlieb
[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
18
TomH

Swift (version courte):

layer.sublayers?.forEach { $0.removeFromSuperlayer() }

12
average Joe

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.

5
Kafu

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)];
3
Amit Limje

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)];
3
Nestor

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.

2
KatokichiSoft

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];
    }
2
zero3nna

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.

1
Er. Vihar

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!

1
pnavk