developer tip

모든 CALayer의 하위 계층 제거

optionbox 2020. 12. 6. 21:27
반응형

모든 CALayer의 하위 계층 제거


레이어의 모든 하위 레이어를 삭제하는 데 문제가 있습니다. 현재 수동으로 수행하지만 불필요한 혼란을 가져옵니다. Google에서 이에 대한 많은 주제를 찾았지만 대답이 없습니다.

나는 다음과 같은 것을 시도했다.

for (CALayer * rootLayer.sublayers의 계층)
{
    [레이어 removeFromSublayer];
}

하지만 작동하지 않았습니다.

또한 rootLayer.sublayers를 별도의 NSArray로 복제하려고 시도했지만 결과는 동일했습니다.

어떤 아이디어?

편집하다:

지금 작동한다고 생각했지만 틀 렸습니다. CALayers에서는 잘 작동하지만 CATextLayers에서는 작동하지 않습니다. 어떤 아이디어?


레이어에서 모든 하위 레이어를 제거하는 가장 간단한 방법은 하위 레이어 속성을 nil로 설정하는 것입니다.

rootLayer.sublayers = nil;


다음이 작동합니다.

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

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

Swift (짧은 버전) :

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


호출 rootLayer.sublayers = nil;하면 충돌이 발생할 수 있습니다 (예 : iOS 8에서 소유하는 뷰에서 removeFromSuperview를 두 번 호출하는 경우 rootLayer).

올바른 방법은 다음과 같아야합니다.

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

반복적으로 호출 copy되는 배열 removeFromSuperlayer이 수정되지 않도록에 대한 호출 이 필요합니다 . 그렇지 않으면 예외가 발생합니다.


모든 하위 계층을 무차별 적으로 제거하면 iOS 7에서 심각한 충돌이 발생하며 이는 프로그램 실행 후반부에 발생할 수 있습니다. 나는 철저하게 모두 사용하여이 테스트 한 rootLayer.sublayers = nil[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]. 엉망이되는 시스템 생성 레이어가 있어야합니다.

고유 한 레이어 배열을 유지하고 직접 제거해야합니다.

[myArrayOfLayersIAddedMyself makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

하위보기 포함 된 경우 self.view.layer.sublayers = nil둘 다 설정 [layer removeFromSuperlayer]하면 충돌이 발생합니다 UIView. CALayersuperLayer 에서 제거 하는 가장 좋은 방법 은 레이어 배열을 유지하는 것입니다. 예를 들어 그 배열은 arrayOfLayers이고,

레이어를 UIView.sublayer추가 할 때마다이 배열에 해당 레이어 추가합니다.

예를 들면

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

제거하는 동안 이것을 호출하십시오.

[arrayOfLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

역 열거를 사용하는 것은 어떻습니까?

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

순서가 정상이면 하위 계층의 그룹이 열거 중에 변경되기 때문입니다. 위 코드의 결과를 알고 싶습니다.


인덱스 0에서 첫 번째 하위 계층 만 삭제하려고했는데 다음과 같이 작동했습니다.

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

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

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);

에서 PrepareForReuseUITableViewCell, 나는의 복사본을 만든 SubLayers내가 이전에 할당 된 이름과 일치하는 것을 재산 및 제거 아무것도 :

    CALayer[] copy = new CALayer[Layer.Sublayers.Length];
    Layer.Sublayers.CopyTo(copy, 0);
    copy.FirstOrDefault(l => l.Name == "borderLayerName")?.RemoveFromSuperLayer();

충돌이 없습니다.

도움이 되었기를 바랍니다!


나는 같은 문제에 직면했고 많은 해결책을 찾았지만 완벽하지는 않습니다.
마지막으로 pnavk의 위 답변 에서 아이디어를 얻었습니다. Xamarin / C # 사용자를위한 코드가 있습니다.
iOS 버전은 다음과 같습니다.

스위프트 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;

The above code will work for bottom border only. You can change the border side as per your requirement.
Here before adding any layer to the controller, I have just run a for loop to check whether any border is already applied or not?
To identify previously added border I use name property of CALayer. And compare that layer before remove from sublayers.
I have tried the same code before using name property, but It creates random crash. But after using name property and comparing name before remove will solve the crash issue.

I hope this will help someone.


For swift3+,You can use this.

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

See here: Apple API Reference

Or you can: yourView.layer.sublayers?.forEach{ $0.removeFromSuperlayer()}


What about doing:

rootLayer.sublayers = @[];

For sure you can do:
self.layer.sublayers=nil;
as suggested by Pascal Bourque. But it's better to call the setter for sublayers property:
[self.layer setSublayers:nil];
To avoid any clean up issues if there might be.

참고URL : https://stackoverflow.com/questions/2067578/removing-all-calayers-sublayers

반응형