删除所有CALayer的子图层

时间:2010-01-14 21:07:42

标签: objective-c cocoa core-animation

我无法删除所有图层的子图层。我目前手动执行此操作,但这会带来不必要的混乱。我在谷歌找到了很多关于此的话题,但没有答案。

我试着这样做:

for(CALayer *layer in rootLayer.sublayers)
{
    [layer removeFromSublayer];
}

但它不起作用。

另外,我试图将rootLayer.sublayers克隆到单独的NSArray中,但结果是一样的。

有什么想法吗?

编辑:

我觉得它现在有效,但我错了。它适用于CALayers,但它不适用于CATextLayers。有什么想法吗?

15 个答案:

答案 0 :(得分:123)

从图层中删除所有子图层的最简单方法是将子图层属性设置为nil:

rootLayer.sublayers = nil;

答案 1 :(得分:33)

以下内容应该有效:

for (CALayer *layer in [[rootLayer.sublayers copy] autorelease]) {
    [layer removeFromSuperlayer];
}

答案 2 :(得分:18)

[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

答案 3 :(得分:10)

Swift(短版):

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

答案 4 :(得分:5)

调用rootLayer.sublayers = nil;可能会导致崩溃(例如,如果在iOS 8下,您在拥有rootLayer的视图上调用removeFromSuperview两次。)

正确的方法应该是:

[[rootLayer.sublayers copy] makeObjectsPerformSelector:@selector(removeFromSuperlayer)]

需要调用copy,以便不会修改迭代调用removeFromSuperlayer的数组,否则会引发异常。

答案 5 :(得分:3)

不加选择地删除所有子图层会导致iOS 7中出现严重崩溃,这可能会在程序执行后发生。我使用rootLayer.sublayers = nil[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]对此进行了彻底的测试。必须有一个系统创建的层搞砸了。

您必须保留自己的图层数组并自行删除它们:

[myArrayOfLayersIAddedMyself makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

答案 6 :(得分:2)

如何使用反向枚举?

NSEnumerator *enumerator = [rootLayer.sublayers reverseObjectEnumerator];
for(CALayer *layer in enumerator) {
    [layer removeFromSuperlayer];
}

因为在枚举期间子层中的组被更改,所以如果顺序正常。 我想知道上面代码的结果。

答案 7 :(得分:2)

我试图删除索引0处的第一个子图层,但这很有效:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    if ([cell.contentView.layer.sublayers count] != 0) {
        [[cell.contentView.layer.sublayers objectAtIndex:0] removeFromSuperlayer];
    }

答案 8 :(得分:2)

如果import ZXingObjC class ZXingObjCWrapper { func encode() { let writer = ZXMultiFormatWriter.writer() .... } } 包含任何子视图,设置self.view.layer.sublayers = nil[layer removeFromSuperlayer]都会导致崩溃。从superLayer中删除UIView的最佳方法是维护一个图层数组。 例如,该数组是arrayOfLayers,

每次在CALayer上添加图层时,都要在此数组中添加该图层...

例如

UIView.sublayer

删除时只需调用它,

[arrayOfLayers addObject:layer];
[self.view.layer addSublayer:layer];

答案 9 :(得分:1)

我必须在Xamarin / C#中这样做。我有UITableViewCell个边框CAShapeLayers。所有上述选项(包括复制数组然后删除图层都会导致崩溃)。这种方法对我有用:

添加CALayer时,我给它起了一个名字:

    var border = new CALayer();
    border.BackgroundColor = color.CGColor;
    border.Frame = new  CGRect(x, y, width, height);
    border.Name = "borderLayerName";
    Layer.AddSublayer(border);

PrepareForReuse的{​​{1}}中,我创建了UITableViewCell属性的副本,并删除了与我之前指定的名称相匹配的所有内容:

SubLayers

没有崩溃。

希望这有帮助!

答案 10 :(得分:1)

我遇到了同样的问题并找到了许多解决方案,但没有一个是完美的 终于从above answer of pnavk我得到了这个想法。那里的代码是Xamarin / C#用户。
iOS版本可能如下:

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


目标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;

以上代码仅适用于底部边框。您可以根据自己的要求更改边框 在将任何图层添加到控制器之前,我刚刚运行了一个for循环来检查是否已经应用了任何边框?
要识别以前添加的边框,我使用CALayer的name属性。并在从子图层中删除之前比较该图层 我在使用name属性之前尝试了相同的代码,但它会创建随机崩溃。但是在使用name属性并在删除之前比较名称将解决崩溃问题 我希望这会对某人有所帮助。

答案 11 :(得分:1)

您只需提供添加的CAlayer的标识符,然后通过搜索将其删除。像这样

 let spinLayer = CAShapeLayer()
 spinLayer.path = UIBezierPath()
 spinLayer.name = "spinLayer"


  func removeAnimation() {
     for layer in progressView.layer.sublayers ?? [CALayer]()
         where layer.name == "spinLayer" {
           layer.removeFromSuperlayer()
       }
   }

答案 12 :(得分:-1)

对于swift3 +,你可以使用它。

yourView.layer.sublayers?.removeAll(keepingCapacity: true)

见这里:Apple API Reference

或者您可以: yourView.layer.sublayers?.forEach{ $0.removeFromSuperlayer()}

答案 13 :(得分:-1)

做什么:

rootLayer.sublayers = @[];

答案 14 :(得分:-2)

当然可以这样做:
self.layer.sublayers=nil;
正如Pascal Bourque所建议的那样。但是为子层属性调用setter会更好:
[self.layer setSublayers:nil];
如果有可能,请避免任何清理问题。