Подтвердить что ты не робот

Удаление всех подслоев CALayer

У меня возникли проблемы с удалением всех подслоев уровня. В настоящее время я делаю это вручную, но это приводит к ненужным беспорядкам. Я нашел много тем об этом в google, но ответа нет.

Я попытался сделать что-то вроде этого:

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

но это не сработало.

Кроме того, я попытался клонировать rootLayer.sublayers в отдельный NSArray, но результат был тот же.

Любые идеи?

Edit:

Я думал, что это работает сейчас, но я был неправ. Он отлично работает с CALayers, но он не работает с CATextLayers. Любые идеи?

4b9b3361

Ответ 1

Самый простой способ удалить все подслои с уровня - установить свойство подслоя на nil:

rootLayer.sublayers = nil;

Ответ 2

Следующее должно работать:

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

Ответ 3

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

Ответ 4

Swift (короткая версия):

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

Ответ 5

Вызов rootLayer.sublayers = nil; может привести к сбою (например, если под iOS 8 вы дважды вызываете removeFromSuperview на видении rootLayer).

Правильный путь:

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

Вызов copy необходим для того, чтобы массив, на который removeFromSuperlayer итеративно вызывается, не изменяется, в противном случае возникает исключение.

Ответ 6

Как использовать обратное перечисление?

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

Поскольку группа в подслоях изменяется во время перечисления, если порядок нормальный. Я хотел бы знать приведенный выше результат кода.

Ответ 7

Без разборки все подслои вызывают неприятные сбои в iOS 7, что может произойти намного позже при выполнении программы. Я проверил это с помощью rootLayer.sublayers = nil и [rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]. Должен быть создан системный слой, который запутывается.

Вы должны сохранить свой собственный массив слоев и удалить их самостоятельно:

[myArrayOfLayersIAddedMyself makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

Ответ 8

Я попытался удалить только первый подуровень с индексом 0, и это сработало:

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

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

Ответ 9

Я должен был сделать это в Xamarin/С#. У меня был 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 на UITableViewCell я создал копию свойства SubLayers и удалил все, что соответствует имени, которое я назначил ранее:

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

Без сбоев.

Надеюсь, это поможет!

Ответ 10

Обе настройки self.view.layer.sublayers = nil и [layer removeFromSuperlayer] приведут к сбою, если UIView содержит какое-либо подвью. Лучший способ удалить CALayer из superLayer - это поддерживать массив слоев. Например, этот массив является arrayOfLayers,

Каждый раз, когда вы добавляете слой на UIView.sublayer, добавляете этот слой в этот массив то есть. [

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

Удаляя только вызов,

[arrayOfLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

Ответ 11

Я столкнулся с той же проблемой и нашел много решений, но ни один из них не идеален. Наконец, из выше ответа pnavk у меня появилась идея. Там код для пользователей Xamarin/С#.
Версия 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


Objective-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 и сравнения имени перед удалением будет устранена проблема сбоя.

Я надеюсь, что это поможет кому-то.

Ответ 12

Конечно, вы можете сделать:
self.layer.sublayers=nil;
как предложил Паскаль Бурк. Но лучше назвать сеттер для свойства подслоев:
[self.layer setSublayers:nil];
Во избежание проблем с очисткой, если это возможно.

Ответ 13

Для swift3 + вы можете использовать это.

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

Смотрите здесь: Справочник API Apple

Или вы можете: yourView.layer.sublayers?.forEach{ $0.removeFromSuperlayer()}

Ответ 14

Что делать:

rootLayer.sublayers = @[];